From fe0db9c71d4c259e5cba5b1f506c89c3846c734e Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Tue, 12 Aug 2025 07:49:05 +0900 Subject: [PATCH 01/23] update rotate operation doc --- src/intrinsic/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index eb0a5336a1f13..82275d8833a44 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -493,9 +493,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::bitreverse => self.bit_reverse(width, args[0].immediate()), sym::rotate_left | sym::rotate_right => { - // TODO(antoyo): implement using algorithm from: + // Using optimized branchless algorithm from: // https://blog.regehr.org/archives/1063 - // for other platforms. + // This implementation uses the pattern (x<>(-n&(width-1))) + // which generates efficient code for other platforms. let is_left = name == sym::rotate_left; let val = args[0].immediate(); let raw_shift = args[1].immediate(); From cbc3860a72bd0675691a7f0ea7678296447b2740 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:15:19 +0000 Subject: [PATCH 02/23] Use rust rather than LLVM target features in the target spec This works better with non-LLVM codegen backends. --- src/gcc_util.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/gcc_util.rs b/src/gcc_util.rs index e4e2dfdd5643b..330b5ff6828d5 100644 --- a/src/gcc_util.rs +++ b/src/gcc_util.rs @@ -33,11 +33,7 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec { // should be taken in cases like these. let mut features = vec![]; - // Features implied by an implicit or explicit `--target`. - features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from)); - - // -Ctarget-features - target_features::flag_to_backend_features(sess, |feature, enable| { + let mut extend_backend_features = |feature: &str, enable: bool| { // We run through `to_gcc_features` when // passing requests down to GCC. This means that all in-language // features also work on the command line instead of having two @@ -48,7 +44,13 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec { .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) .map(|feature| if !enable { format!("-{}", feature) } else { feature.to_string() }), ); - }); + }; + + // Features implied by an implicit or explicit `--target`. + target_features::target_spec_to_backend_features(sess, &mut extend_backend_features); + + // -Ctarget-features + target_features::flag_to_backend_features(sess, extend_backend_features); gcc_features_by_flags(sess, &mut features); @@ -66,6 +68,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> (&Arch::X86 | &Arch::X86_64, "rdrand") => smallvec!["rdrnd"], (&Arch::X86 | &Arch::X86_64, "bmi1") => smallvec!["bmi"], (&Arch::X86 | &Arch::X86_64, "cmpxchg16b") => smallvec!["cx16"], + (&Arch::X86 | &Arch::X86_64, "lahfsahf") => smallvec!["sahf"], (&Arch::X86 | &Arch::X86_64, "avx512vaes") => smallvec!["vaes"], (&Arch::X86 | &Arch::X86_64, "avx512gfni") => smallvec!["gfni"], (&Arch::X86 | &Arch::X86_64, "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], From 2af849a6e5c5706528efdf7ca3507525b64a074b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 26 Nov 2025 19:41:43 +0100 Subject: [PATCH 03/23] Merge commit '55171cfa8b53970e06dcd2f5f2e2b8d82eeb0885' into subtree-update_cg_gcc_2025-11-26 --- .github/workflows/failures.yml | 2 - .github/workflows/gcc12.yml | 6 -- .github/workflows/release.yml | 3 + .github/workflows/stdarch.yml | 9 +- Cargo.lock | 8 +- Cargo.toml | 6 +- build_system/src/build.rs | 24 +++-- build_system/src/config.rs | 13 --- build_system/src/test.rs | 14 +-- doc/tips.md | 8 ++ libgccjit.version | 2 +- rust-toolchain | 2 +- src/attributes.rs | 2 +- src/back/lto.rs | 1 + src/builder.rs | 3 +- src/consts.rs | 3 +- src/context.rs | 4 +- src/declare.rs | 2 +- src/intrinsic/archs.rs | 20 +--- src/intrinsic/llvm.rs | 13 ++- src/intrinsic/simd.rs | 190 ++++++++++++++++++++++++++++++++- src/lib.rs | 59 +++++++--- src/mono_item.rs | 3 +- src/type_.rs | 2 +- tests/failing-lto-tests.txt | 7 ++ tests/failing-ui-tests.txt | 13 ++- tests/lang_tests_common.rs | 26 +---- tools/generate_intrinsics.py | 3 +- 28 files changed, 315 insertions(+), 133 deletions(-) create mode 100644 tests/failing-lto-tests.txt diff --git a/.github/workflows/failures.yml b/.github/workflows/failures.yml index 67b7fbe4478bd..aa4b4dc22c3e4 100644 --- a/.github/workflows/failures.yml +++ b/.github/workflows/failures.yml @@ -54,8 +54,6 @@ jobs: if: matrix.libgccjit_version.gcc == 'libgccjit12.so' run: | echo 'gcc-path = "/usr/lib/gcc/x86_64-linux-gnu/12"' > config.toml - echo "LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV - name: Download artifact if: matrix.libgccjit_version.gcc != 'libgccjit12.so' diff --git a/.github/workflows/gcc12.yml b/.github/workflows/gcc12.yml index da9a1506855c3..55b090894b4af 100644 --- a/.github/workflows/gcc12.yml +++ b/.github/workflows/gcc12.yml @@ -51,12 +51,6 @@ jobs: - name: Setup path to libgccjit run: echo 'gcc-path = "/usr/lib/gcc/x86_64-linux-gnu/12"' > config.toml - - name: Set env - run: | - echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - echo "LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/12" >> $GITHUB_ENV - #- name: Cache rust repository ## We only clone the rust repository for rustc tests #if: ${{ contains(matrix.commands, 'rustc') }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52f94dc2970a4..895d66f9a4acd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -72,6 +72,9 @@ jobs: git config --global user.name "User" ./y.sh prepare + - name: Add more failing tests (some panic and debuginfo tests fail) + run: cat tests/failing-lto-tests.txt >> tests/failing-ui-tests.txt + - name: Run tests run: | # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. diff --git a/.github/workflows/stdarch.yml b/.github/workflows/stdarch.yml index 184f122cc1c17..c0a0e3344cc2b 100644 --- a/.github/workflows/stdarch.yml +++ b/.github/workflows/stdarch.yml @@ -59,9 +59,8 @@ jobs: sudo ln -s /usr/share/intel-sde/sde /usr/bin/sde sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64 - - name: Set env + - name: Set config run: | - echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV echo 'download-gccjit = true' > config.toml - name: Build @@ -69,12 +68,6 @@ jobs: ./y.sh prepare --only-libcore ./y.sh build --sysroot --release --release-sysroot - - name: Set env (part 2) - run: | - # Set the `LD_LIBRARY_PATH` and `LIBRARY_PATH` env variables... - echo "LD_LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - echo "LIBRARY_PATH="$(./y.sh info | grep -v Using) >> $GITHUB_ENV - - name: Clean if: ${{ !matrix.cargo_runner }} run: | diff --git a/Cargo.lock b/Cargo.lock index 181d3aa89bc89..00bdacaca6762 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,18 +56,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.10.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60362e038e71e4bdc1a5b23fb45e1aba587b5947fe0db58f4871d95608f89eca" +checksum = "ff80f4d6d0749eab3a69122210b3a1fdd52edb6162781aadd7c4842e26983683" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.9.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd542c8414e122217551c6af6b7d33acf51a227aee85276f218c087525e01bb" +checksum = "263da4f60b7bb5d6a5b21efda961741051ebdbf0e380a09118b03cce66a8c77e" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index d3ff2757857b1..18847f50d46a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,11 +24,11 @@ default = ["master"] [dependencies] object = { version = "0.37.0", default-features = false, features = ["std", "read"] } tempfile = "3.20" -gccjit = "2.10" -#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } +gccjit = { version = "3.1.1", features = ["dlopen"] } +#gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] } # Local copy. -#gccjit = { path = "../gccjit.rs" } +#gccjit = { path = "../gccjit.rs", features = ["dlopen"] } [dev-dependencies] boml = "0.3.1" diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 6aa5faec4c81e..56503b239a3b5 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use std::ffi::OsStr; use std::fs; -use std::path::Path; +use std::os::unix::fs::symlink; +use std::path::{Path, PathBuf}; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ @@ -100,6 +101,18 @@ fn cleanup_sysroot_previous_build(library_dir: &Path) { pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Result<(), String> { let start_dir = get_sysroot_dir(); + // Symlink libgccjit.so to sysroot. + let lib_path = start_dir.join("sysroot").join("lib"); + let libgccjit_path = + PathBuf::from(config.gcc_path.as_ref().expect("libgccjit should be set by this point")) + .join("libgccjit.so"); + let libgccjit_in_sysroot_path = lib_path.join("libgccjit.so"); + // First remove the file to be able to create the symlink even when the file already exists. + let _ = fs::remove_file(&libgccjit_in_sysroot_path); + create_dir(&lib_path)?; + symlink(libgccjit_path, libgccjit_in_sysroot_path) + .map_err(|error| format!("Cannot create symlink for libgccjit.so: {}", error))?; + let library_dir = start_dir.join("sysroot_src").join("library"); cleanup_sysroot_previous_build(&library_dir); @@ -148,7 +161,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu run_command_with_output_and_env(&args, Some(&sysroot_dir), Some(&env))?; // Copy files to sysroot - let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple)); + let sysroot_path = lib_path.join(format!("rustlib/{}/lib/", config.target_triple)); // To avoid errors like "multiple candidates for `rmeta` dependency `core` found", we clean the // sysroot directory before copying the sysroot build artifacts. let _ = fs::remove_dir_all(&sysroot_path); @@ -175,13 +188,6 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu fn build_codegen(args: &mut BuildArg) -> Result<(), String> { let mut env = HashMap::new(); - let gcc_path = - args.config_info.gcc_path.clone().expect( - "The config module should have emitted an error if the GCC path wasn't provided", - ); - env.insert("LD_LIBRARY_PATH".to_string(), gcc_path.clone()); - env.insert("LIBRARY_PATH".to_string(), gcc_path); - if args.config_info.no_default_features { env.insert("RUSTFLAGS".to_string(), "-Csymbol-mangling-version=v0".to_string()); } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index a5f802e293a94..19255e1ba2b2c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -429,19 +429,6 @@ impl ConfigInfo { // display metadata load errors env.insert("RUSTC_LOG".to_string(), "warn".to_string()); - let sysroot = current_dir - .join(get_sysroot_dir()) - .join(format!("sysroot/lib/rustlib/{}/lib", self.target_triple)); - let ld_library_path = format!( - "{target}:{sysroot}:{gcc_path}", - target = self.cargo_target_dir, - sysroot = sysroot.display(), - gcc_path = gcc_path, - ); - env.insert("LIBRARY_PATH".to_string(), ld_library_path.clone()); - env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone()); - env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path); - // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc diff --git a/build_system/src/test.rs b/build_system/src/test.rs index dbdaf2a63ef29..8aabfa894ce08 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -214,14 +214,6 @@ fn cargo_tests(test_env: &Env, test_args: &TestArg) -> Result<(), String> { // 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(), @@ -1065,6 +1057,7 @@ where &test_dir, &"--compiletest-rustc-args", &rustc_args, + &"--bypass-ignore-backends", ]; if run_ignored_tests { @@ -1275,11 +1268,6 @@ pub fn run() -> Result<(), String> { if !args.use_system_gcc { args.config_info.setup_gcc_path()?; - let gcc_path = args.config_info.gcc_path.clone().expect( - "The config module should have emitted an error if the GCC path wasn't provided", - ); - env.insert("LIBRARY_PATH".to_string(), gcc_path.clone()); - env.insert("LD_LIBRARY_PATH".to_string(), gcc_path); } build_if_no_backend(&env, &args)?; diff --git a/doc/tips.md b/doc/tips.md index e62c3402a292d..38bc98c02d926 100644 --- a/doc/tips.md +++ b/doc/tips.md @@ -9,6 +9,14 @@ be useful. CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../y.sh cargo build ``` +### How to send arguments to GCC + +The `-Cllvm-args` `rustc` flag is repurposed by `rustc_codegen_gcc` to pass arguments directly to the GCC backend. You can use it via the `CG_RUSTFLAGS` environment variable. For example, to pass a `-f` flag to GCC: + +``` +CG_RUSTFLAGS="-Cllvm-args=-fflag-name" ../y.sh cargo build +``` + ### How to see the personality functions in the asm dump ``` diff --git a/libgccjit.version b/libgccjit.version index b8d4166542bcd..bab62f6423655 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -28b84db392ac0a572f1a2a2a1317aa5f2bc742cb +0081ca6631abdfa02bf42bc85aaf507b8a0e6beb diff --git a/rust-toolchain b/rust-toolchain index 9813bbea00c41..f9645451e964d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-11-04" +channel = "nightly-2025-11-24" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/attributes.rs b/src/attributes.rs index 5df1dc41b01dd..cd8c1206c821b 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -86,7 +86,7 @@ fn inline_attr<'gcc, 'tcx>( /// attributes. pub fn from_fn_attrs<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, - #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, + #[cfg_attr(not(feature = "master"), expect(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); diff --git a/src/back/lto.rs b/src/back/lto.rs index 404064fb7a060..840f51c0685d7 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -633,6 +633,7 @@ pub fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } }*/ + // FIXME: switch to #[expect] when the clippy bug is fixed. #[allow(clippy::let_and_return)] module } diff --git a/src/builder.rs b/src/builder.rs index 132c43ef3cdad..c0519f7a68e28 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1481,7 +1481,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { variable.to_rvalue() } - #[allow(dead_code)] fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> { unimplemented!(); } @@ -2517,7 +2516,7 @@ impl ToGccComp for RealPredicate { } #[repr(C)] -#[allow(non_camel_case_types)] +#[expect(non_camel_case_types)] enum MemOrdering { __ATOMIC_RELAXED, __ATOMIC_CONSUME, diff --git a/src/consts.rs b/src/consts.rs index ec7d4b285a3fd..6fb96f8832b93 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -58,7 +58,6 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { global_value } - #[cfg_attr(not(feature = "master"), allow(unused_mut))] fn codegen_static(&mut self, def_id: DefId) { let attrs = self.tcx.codegen_fn_attrs(def_id); @@ -162,7 +161,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // TODO(antoyo) } - #[cfg_attr(not(feature = "master"), allow(unused_variables))] + #[cfg_attr(not(feature = "master"), expect(unused_variables))] pub fn add_used_function(&self, function: Function<'gcc>) { #[cfg(feature = "master")] function.add_attribute(FnAttribute::Used); diff --git a/src/context.rs b/src/context.rs index c9ae96777de44..dbb89a4ff7dba 100644 --- a/src/context.rs +++ b/src/context.rs @@ -28,7 +28,7 @@ use crate::abi::conv_to_fn_attribute; use crate::callee::get_fn; use crate::common::SignType; -#[cfg_attr(not(feature = "master"), allow(dead_code))] +#[cfg_attr(not(feature = "master"), expect(dead_code))] pub struct CodegenCx<'gcc, 'tcx> { /// A cache of converted ConstAllocs pub const_cache: RefCell>>, @@ -132,7 +132,7 @@ pub struct CodegenCx<'gcc, 'tcx> { } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - #[allow(clippy::too_many_arguments)] + #[expect(clippy::too_many_arguments)] pub fn new( context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, diff --git a/src/declare.rs b/src/declare.rs index 691fd8729e39a..42d6fb17a88bc 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -156,7 +156,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { /// /// If there’s a value with the same name already declared, the function will /// update the declaration and return existing Value instead. -#[allow(clippy::let_and_return)] +#[expect(clippy::let_and_return)] fn declare_raw_fn<'gcc>( cx: &CodegenCx<'gcc, '_>, name: &str, diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index c51bcbcedd677..bb8bcbf66f380 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -10,7 +10,7 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { }; match arch { "AMDGPU" => { - #[allow(non_snake_case)] + #[expect(non_snake_case)] fn AMDGPU(name: &str, full_name: &str) -> &'static str { match name { // AMDGPU @@ -48,7 +48,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { AMDGPU(name, full_name) } "aarch64" => { - #[allow(non_snake_case)] fn aarch64(name: &str, full_name: &str) -> &'static str { match name { // aarch64 @@ -81,7 +80,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { aarch64(name, full_name) } "amdgcn" => { - #[allow(non_snake_case)] fn amdgcn(name: &str, full_name: &str) -> &'static str { match name { // amdgcn @@ -524,7 +522,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { amdgcn(name, full_name) } "arm" => { - #[allow(non_snake_case)] fn arm(name: &str, full_name: &str) -> &'static str { match name { // arm @@ -633,7 +630,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { arm(name, full_name) } "bpf" => { - #[allow(non_snake_case)] fn bpf(name: &str, full_name: &str) -> &'static str { match name { // bpf @@ -655,7 +651,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { bpf(name, full_name) } "cuda" => { - #[allow(non_snake_case)] fn cuda(name: &str, full_name: &str) -> &'static str { match name { // cuda @@ -666,7 +661,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { cuda(name, full_name) } "hexagon" => { - #[allow(non_snake_case)] fn hexagon(name: &str, full_name: &str) -> &'static str { match name { // hexagon @@ -2653,7 +2647,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { hexagon(name, full_name) } "loongarch" => { - #[allow(non_snake_case)] fn loongarch(name: &str, full_name: &str) -> &'static str { match name { // loongarch @@ -4162,7 +4155,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { loongarch(name, full_name) } "mips" => { - #[allow(non_snake_case)] fn mips(name: &str, full_name: &str) -> &'static str { match name { // mips @@ -4843,7 +4835,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { mips(name, full_name) } "nvvm" => { - #[allow(non_snake_case)] fn nvvm(name: &str, full_name: &str) -> &'static str { match name { // nvvm @@ -5652,7 +5643,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { nvvm(name, full_name) } "ppc" => { - #[allow(non_snake_case)] fn ppc(name: &str, full_name: &str) -> &'static str { match name { // ppc @@ -6245,7 +6235,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { ppc(name, full_name) } "ptx" => { - #[allow(non_snake_case)] fn ptx(name: &str, full_name: &str) -> &'static str { match name { // ptx @@ -6273,7 +6262,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { ptx(name, full_name) } "r600" => { - #[allow(non_snake_case)] fn r600(name: &str, full_name: &str) -> &'static str { match name { // r600 @@ -6298,7 +6286,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { r600(name, full_name) } "riscv" => { - #[allow(non_snake_case)] fn riscv(name: &str, full_name: &str) -> &'static str { match name { // riscv @@ -6332,7 +6319,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { riscv(name, full_name) } "s390" => { - #[allow(non_snake_case)] fn s390(name: &str, full_name: &str) -> &'static str { match name { // s390 @@ -6526,7 +6512,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { s390(name, full_name) } "spv" => { - #[allow(non_snake_case)] fn spv(name: &str, full_name: &str) -> &'static str { match name { // spv @@ -6543,7 +6528,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { spv(name, full_name) } "ve" => { - #[allow(non_snake_case)] fn ve(name: &str, full_name: &str) -> &'static str { match name { // ve @@ -7816,7 +7800,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { ve(name, full_name) } "x86" => { - #[allow(non_snake_case)] fn x86(name: &str, full_name: &str) -> &'static str { match name { // x86 @@ -10384,7 +10367,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { x86(name, full_name) } "xcore" => { - #[allow(non_snake_case)] fn xcore(name: &str, full_name: &str) -> &'static str { match name { // xcore diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 39dba28b24c9e..e3d189c95ced5 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -85,7 +85,7 @@ fn wide_aes_output_type<'a, 'gcc, 'tcx>( (aes_output_type.as_type(), field1, field2) } -#[cfg_attr(not(feature = "master"), allow(unused_variables))] +#[cfg_attr(not(feature = "master"), expect(unused_variables))] pub fn adjust_function<'gcc>( context: &'gcc Context<'gcc>, func_name: &str, @@ -1573,14 +1573,25 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.tileloadd64" => "__builtin_trap", "llvm.x86.tilerelease" => "__builtin_trap", "llvm.x86.tilestored64" => "__builtin_trap", + "llvm.x86.tileloaddrs64" => "__builtin_trap", "llvm.x86.tileloaddt164" => "__builtin_trap", + "llvm.x86.tileloaddrst164" => "__builtin_trap", "llvm.x86.tilezero" => "__builtin_trap", + "llvm.x86.tilemovrow" => "__builtin_trap", + "llvm.x86.tdpbhf8ps" => "__builtin_trap", + "llvm.x86.tdphbf8ps" => "__builtin_trap", + "llvm.x86.tdpbf8ps" => "__builtin_trap", + "llvm.x86.tdphf8ps" => "__builtin_trap", "llvm.x86.tdpbf16ps" => "__builtin_trap", "llvm.x86.tdpbssd" => "__builtin_trap", "llvm.x86.tdpbsud" => "__builtin_trap", "llvm.x86.tdpbusd" => "__builtin_trap", "llvm.x86.tdpbuud" => "__builtin_trap", "llvm.x86.tdpfp16ps" => "__builtin_trap", + "llvm.x86.tmmultf32ps" => "__builtin_trap", + "llvm.x86.tcvtrowps2phh" => "__builtin_trap", + "llvm.x86.tcvtrowps2phl" => "__builtin_trap", + "llvm.x86.tcvtrowd2ps" => "__builtin_trap", "llvm.x86.tcmmimfp16ps" => "__builtin_trap", "llvm.x86.tcmmrlfp16ps" => "__builtin_trap", diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 41363d6313d69..c7ed887b30d02 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -53,6 +53,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }; } + // TODO(antoyo): refactor with the above require_simd macro that was changed in cg_llvm. + #[cfg(feature = "master")] + macro_rules! require_simd2 { + ($ty: expr, $variant:ident) => {{ + require!($ty.is_simd(), InvalidMonomorphization::$variant { span, name, ty: $ty }); + $ty.simd_size_and_type(bx.tcx()) + }}; + } + if name == sym::simd_select_bitmask { require_simd!( args[1].layout.ty, @@ -464,9 +473,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( m_len == v_len, InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); - // TODO: also support unsigned integers. match *m_elem_ty.kind() { - ty::Int(_) => {} + ty::Int(_) | ty::Uint(_) => {} _ => return_error!(InvalidMonomorphization::MaskWrongElementType { span, name, @@ -1454,6 +1462,184 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bitwise_red!(simd_reduce_all: BinaryOp::BitwiseAnd, true); bitwise_red!(simd_reduce_any: BinaryOp::BitwiseOr, true); + #[cfg(feature = "master")] + if name == sym::simd_masked_load { + // simd_masked_load<_, _, _, const ALIGN: SimdAlign>(mask: , pointer: *_ T, values: ) -> + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + // Loads contiguous elements from memory behind `pointer`, but only for + // those lanes whose `mask` bit is enabled. + // The memory addresses corresponding to the “off” lanes are not accessed. + + // TODO: handle the alignment. + + // The element type of the "mask" argument must be a signed integer type of any width + let mask_ty = in_ty; + let mask_len = in_len; + + // The second argument must be a pointer matching the element type + let pointer_ty = args[1].layout.ty; + + // The last argument is a passthrough vector providing values for disabled lanes + let values_ty = args[2].layout.ty; + let (values_len, values_elem) = require_simd2!(values_ty, SimdThird); + + require_simd2!(ret_ty, SimdReturn); + + // Of the same length: + require!( + values_len == mask_len, + InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len: mask_len, + in_ty: mask_ty, + arg_ty: values_ty, + out_len: values_len + } + ); + + // The return type must match the last argument type + require!( + ret_ty == values_ty, + InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty } + ); + + require!( + matches!( + *pointer_ty.kind(), + ty::RawPtr(p_ty, _) if p_ty == values_elem && p_ty.kind() == values_elem.kind() + ), + InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: values_elem, + second_arg: pointer_ty, + in_elem: values_elem, + in_ty: values_ty, + mutability: ExpectedPointerMutability::Not, + } + ); + + let mask = args[0].immediate(); + + let pointer = args[1].immediate(); + let default = args[2].immediate(); + let default_type = default.get_type(); + let vector_type = default_type.unqualified().dyncast_vector().expect("vector type"); + let value_type = vector_type.get_element_type(); + let new_pointer_type = value_type.make_pointer(); + + let pointer = bx.context.new_cast(None, pointer, new_pointer_type); + + let mask_vector_type = mask.get_type().unqualified().dyncast_vector().expect("vector type"); + let elem_type = mask_vector_type.get_element_type(); + let zero = bx.context.new_rvalue_zero(elem_type); + let mut elements = vec![]; + for i in 0..mask_len { + let i = bx.context.new_rvalue_from_int(bx.int_type, i as i32); + let mask = bx.context.new_vector_access(None, mask, i).to_rvalue(); + let mask = bx.context.new_comparison(None, ComparisonOp::NotEquals, mask, zero); + let then_val = bx.context.new_array_access(None, pointer, i).to_rvalue(); + let else_val = bx.context.new_vector_access(None, default, i).to_rvalue(); + let element = bx.select(mask, then_val, else_val); + elements.push(element); + } + let result = bx.context.new_rvalue_from_vector(None, default_type, &elements); + return Ok(result); + } + + #[cfg(feature = "master")] + if name == sym::simd_masked_store { + // simd_masked_store<_, _, _, const ALIGN: SimdAlign>(mask: , pointer: *mut T, values: ) -> () + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + // Stores contiguous elements to memory behind `pointer`, but only for + // those lanes whose `mask` bit is enabled. + // The memory addresses corresponding to the “off” lanes are not accessed. + + // TODO: handle the alignment. + + // The element type of the "mask" argument must be a signed integer type of any width + let mask_ty = in_ty; + let mask_len = in_len; + + // The second argument must be a pointer matching the element type + let pointer_ty = args[1].layout.ty; + + // The last argument specifies the values to store to memory + let values_ty = args[2].layout.ty; + let (values_len, values_elem) = require_simd2!(values_ty, SimdThird); + + // Of the same length: + require!( + values_len == mask_len, + InvalidMonomorphization::ThirdArgumentLength { + span, + name, + in_len: mask_len, + in_ty: mask_ty, + arg_ty: values_ty, + out_len: values_len + } + ); + + // The second argument must be a mutable pointer type matching the element type + require!( + matches!( + *pointer_ty.kind(), + ty::RawPtr(p_ty, p_mutbl) + if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut() + ), + InvalidMonomorphization::ExpectedElementType { + span, + name, + expected_element: values_elem, + second_arg: pointer_ty, + in_elem: values_elem, + in_ty: values_ty, + mutability: ExpectedPointerMutability::Mut, + } + ); + + let mask = args[0].immediate(); + let pointer = args[1].immediate(); + let values = args[2].immediate(); + let values_type = values.get_type(); + let vector_type = values_type.unqualified().dyncast_vector().expect("vector type"); + let value_type = vector_type.get_element_type(); + let new_pointer_type = value_type.make_pointer(); + + let pointer = bx.context.new_cast(None, pointer, new_pointer_type); + + let vector_type = mask.get_type().unqualified().dyncast_vector().expect("vector type"); + let elem_type = vector_type.get_element_type(); + let zero = bx.context.new_rvalue_zero(elem_type); + for i in 0..mask_len { + let i = bx.context.new_rvalue_from_int(bx.int_type, i as i32); + let mask = bx.context.new_vector_access(None, mask, i).to_rvalue(); + let mask = bx.context.new_comparison(None, ComparisonOp::NotEquals, mask, zero); + + let after_block = bx.current_func().new_block("after"); + let then_block = bx.current_func().new_block("then"); + bx.llbb().end_with_conditional(None, mask, then_block, after_block); + + bx.switch_to_block(then_block); + let lvalue = bx.context.new_array_access(None, pointer, i); + let value = bx.context.new_vector_access(None, values, i).to_rvalue(); + bx.llbb().add_assignment(None, lvalue, value); + bx.llbb().end_with_jump(None, after_block); + + bx.switch_to_block(after_block); + } + + let dummy_value = bx.context.new_rvalue_zero(bx.int_type); + + return Ok(dummy_value); + } + unimplemented!("simd {}", name); } diff --git a/src/lib.rs b/src/lib.rs index 409b7886740a4..662e303f94f2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![deny(clippy::pattern_type_mismatch)] -#![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] +#![expect(clippy::uninlined_format_args)] // The rustc crates we need extern crate rustc_abi; @@ -43,7 +43,7 @@ extern crate rustc_target; extern crate rustc_type_ir; // This prevents duplicating functions and statics that are already part of the host rustc process. -#[allow(unused_extern_crates)] +#[expect(unused_extern_crates)] extern crate rustc_driver; mod abi; @@ -69,9 +69,10 @@ mod type_; mod type_of; use std::any::Any; +use std::ffi::CString; use std::fmt::Debug; use std::ops::Deref; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; @@ -142,7 +143,7 @@ impl TargetInfo { #[derive(Clone)] pub struct LockedTargetInfo { - info: Arc>>, + info: Arc>>>, } impl Debug for LockedTargetInfo { @@ -153,11 +154,21 @@ impl Debug for LockedTargetInfo { impl LockedTargetInfo { fn cpu_supports(&self, feature: &str) -> bool { - self.info.lock().expect("lock").cpu_supports(feature) + self.info + .lock() + .expect("lock") + .as_ref() + .expect("target info not initialized") + .cpu_supports(feature) } fn supports_target_dependent_type(&self, typ: CType) -> bool { - self.info.lock().expect("lock").supports_target_dependent_type(typ) + self.info + .lock() + .expect("lock") + .as_ref() + .expect("target info not initialized") + .supports_target_dependent_type(typ) } } @@ -169,6 +180,23 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); +fn load_libgccjit_if_needed(sysroot_path: &Path) { + if gccjit::is_loaded() { + // Do not load a libgccjit second time. + return; + } + + let sysroot_lib_dir = sysroot_path.join("lib"); + let libgccjit_target_lib_file = sysroot_lib_dir.join("libgccjit.so"); + let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); + + let string = CString::new(path).expect("string to libgccjit path"); + + if let Err(error) = gccjit::load(&string) { + panic!("Cannot load libgccjit.so: {}", error); + } +} + impl CodegenBackend for GccCodegenBackend { fn locale_resource(&self) -> &'static str { crate::DEFAULT_LOCALE_RESOURCE @@ -178,10 +206,12 @@ impl CodegenBackend for GccCodegenBackend { "gcc" } - fn init(&self, _sess: &Session) { + fn init(&self, sess: &Session) { + load_libgccjit_if_needed(sess.opts.sysroot.path()); + #[cfg(feature = "master")] { - let target_cpu = target_cpu(_sess); + let target_cpu = target_cpu(sess); // Get the second TargetInfo with the correct CPU features by setting the arch. let context = Context::default(); @@ -189,7 +219,8 @@ impl CodegenBackend for GccCodegenBackend { context.add_command_line_option(format!("-march={}", target_cpu)); } - **self.target_info.info.lock().expect("lock") = context.get_target_info(); + *self.target_info.info.lock().expect("lock") = + IntoDynSyncSend(Some(context.get_target_info())); } #[cfg(feature = "master")] @@ -217,6 +248,9 @@ impl CodegenBackend for GccCodegenBackend { .info .lock() .expect("lock") + .0 + .as_ref() + .expect("target info not initialized") .supports_128bit_integers .store(check_context.get_last_error() == Ok(None), Ordering::SeqCst); } @@ -438,13 +472,12 @@ pub fn __rustc_codegen_backend() -> Box { let info = { // Check whether the target supports 128-bit integers, and sized floating point types (like // Float16). - let context = Context::default(); - Arc::new(Mutex::new(IntoDynSyncSend(context.get_target_info()))) + Arc::new(Mutex::new(IntoDynSyncSend(None))) }; #[cfg(not(feature = "master"))] - let info = Arc::new(Mutex::new(IntoDynSyncSend(TargetInfo { + let info = Arc::new(Mutex::new(IntoDynSyncSend(Some(TargetInfo { supports_128bit_integers: AtomicBool::new(false), - }))); + })))); Box::new(GccCodegenBackend { lto_supported: Arc::new(AtomicBool::new(false)), diff --git a/src/mono_item.rs b/src/mono_item.rs index 35d44d21bcbf6..31c03eddaca56 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -15,7 +15,7 @@ use crate::type_of::LayoutGccExt; use crate::{attributes, base}; impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - #[cfg_attr(not(feature = "master"), allow(unused_variables))] + #[cfg_attr(not(feature = "master"), expect(unused_variables))] fn predefine_static( &mut self, def_id: DefId, @@ -41,7 +41,6 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.instances.borrow_mut().insert(instance, global); } - #[cfg_attr(not(feature = "master"), allow(unused_variables))] fn predefine_fn( &mut self, instance: Instance<'tcx>, diff --git a/src/type_.rs b/src/type_.rs index 15a0206607e12..d356b6af260ae 100644 --- a/src/type_.rs +++ b/src/type_.rs @@ -299,7 +299,7 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { value.get_type() } - #[cfg_attr(feature = "master", allow(unused_mut))] + #[cfg_attr(feature = "master", expect(unused_mut))] fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { #[cfg(not(feature = "master"))] if let Some(struct_type) = ty.is_struct() diff --git a/tests/failing-lto-tests.txt b/tests/failing-lto-tests.txt new file mode 100644 index 0000000000000..c45fc0776588e --- /dev/null +++ b/tests/failing-lto-tests.txt @@ -0,0 +1,7 @@ +tests/ui/lto/all-crates.rs +tests/ui/lto/debuginfo-lto-alloc.rs +tests/ui/panic-runtime/lto-unwind.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 diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index cc00432ceb54e..2380bd0fc137f 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -8,7 +8,6 @@ tests/ui/iterators/iter-sum-overflow-overflow-checks.rs tests/ui/mir/mir_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs tests/ui/mir/mir_match_guard_let_chains_drop_order.rs -tests/ui/panics/oom-panic-unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs tests/ui/panic-runtime/link-to-abort.rs @@ -77,3 +76,15 @@ tests/ui/explicit-tail-calls/recursion-etc.rs tests/ui/explicit-tail-calls/indexer.rs tests/ui/explicit-tail-calls/drop-order.rs tests/ui/c-variadic/valid.rs +tests/ui/c-variadic/inherent-method.rs +tests/ui/c-variadic/trait-method.rs +tests/ui/explicit-tail-calls/become-cast-return.rs +tests/ui/explicit-tail-calls/become-indirect-return.rs +tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs +tests/ui/sanitizer/kcfi-c-variadic.rs +tests/ui/sanitizer/kcfi/fn-trait-objects.rs +tests/ui/statics/const_generics.rs +tests/ui/test-attrs/test-panic-while-printing.rs +tests/ui/thir-print/offset_of.rs +tests/ui/iterators/rangefrom-overflow-debug.rs +tests/ui/iterators/rangefrom-overflow-overflow-checks.rs diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 9abe97b108765..311f256b76008 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -2,11 +2,10 @@ #![allow(clippy::uninlined_format_args)] -use std::env::{self, current_dir}; +use std::env::current_dir; use std::path::{Path, PathBuf}; use std::process::Command; -use boml::Toml; use lang_tester::LangTester; use tempfile::TempDir; @@ -23,29 +22,6 @@ pub fn main_inner(profile: Profile) { let current_dir = current_dir().expect("current dir"); let current_dir = current_dir.to_str().expect("current dir").to_string(); - let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - - let gcc_path = std::fs::read_to_string(manifest_dir.join("config.toml")) - .ok() - .and_then(|v| { - let toml = Toml::parse(&v).expect("Failed to parse `config.toml`"); - toml.get_string("gcc-path").map(PathBuf::from).ok() - }) - .unwrap_or_else(|| { - // then we try to retrieve it from the `target` folder. - let commit = include_str!("../libgccjit.version").trim(); - Path::new("build/libgccjit").join(commit) - }); - - let gcc_path = Path::new(&gcc_path) - .canonicalize() - .expect("failed to get absolute path of `gcc-path`") - .display() - .to_string(); - unsafe { - env::set_var("LD_LIBRARY_PATH", gcc_path); - } - fn rust_filter(path: &Path) -> bool { path.is_file() && path.extension().expect("extension").to_str().expect("to_str") == "rs" } diff --git a/tools/generate_intrinsics.py b/tools/generate_intrinsics.py index 88927f39b93e4..767082c23cce8 100644 --- a/tools/generate_intrinsics.py +++ b/tools/generate_intrinsics.py @@ -183,7 +183,8 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): for arch in archs: if len(intrinsics[arch]) == 0: continue - out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch,arch)) + attribute = "#[expect(non_snake_case)]" if arch[0].isupper() else "" + out.write("\"{}\" => {{ {} fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch, attribute, arch)) intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: From a7ea98bf2c8d4688aae2d238d856c14282fbbab6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 26 Nov 2025 11:42:42 +0100 Subject: [PATCH 04/23] Update GCC commit --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index bab62f6423655..b8d4166542bcd 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -0081ca6631abdfa02bf42bc85aaf507b8a0e6beb +28b84db392ac0a572f1a2a2a1317aa5f2bc742cb From 8059907cef079081bd51d2adddc8769dddd16728 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 26 Nov 2025 20:11:18 +0100 Subject: [PATCH 05/23] Update GCC submodule --- libgccjit.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgccjit.version b/libgccjit.version index b8d4166542bcd..bab62f6423655 100644 --- a/libgccjit.version +++ b/libgccjit.version @@ -1 +1 @@ -28b84db392ac0a572f1a2a2a1317aa5f2bc742cb +0081ca6631abdfa02bf42bc85aaf507b8a0e6beb From 4054d07d38c7c8cdbdc2604cf6268fa52dde0165 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:55:38 +0000 Subject: [PATCH 06/23] Remove -Zoom=panic There are major questions remaining about the reentrancy that this allows. It doesn't have any users on github outside of a single project that uses it in a panic=abort project to show backtraces. It can still be emulated through #[alloc_error_handler] or set_alloc_error_hook depending on if you use the standard library or not. And finally it makes it harder to do various improvements to the allocator shim. --- src/allocator.rs | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 647569694b04d..1f464d7e1226f 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,12 +1,11 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; -use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; +use gccjit::{Context, FunctionType, ToRValue, Type}; use rustc_ast::expand::allocator::{ AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::OomStrategy; use rustc_symbol_mangling::mangle_internal_symbol; use crate::GccContext; @@ -59,14 +58,6 @@ pub(crate) unsafe fn codegen( create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } - create_const_value_function( - tcx, - context, - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - i8, - context.new_rvalue_from_int(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as i32), - ); - create_wrapper_function( tcx, context, @@ -77,34 +68,6 @@ pub(crate) unsafe fn codegen( ); } -fn create_const_value_function( - tcx: TyCtxt<'_>, - context: &Context<'_>, - name: &str, - output: Type<'_>, - value: RValue<'_>, -) { - let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); - - #[cfg(feature = "master")] - { - func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - - // FIXME(antoyo): cg_llvm sets AlwaysInline, but AlwaysInline is different in GCC and using - // it here will causes linking errors when using LTO. - func.add_attribute(FnAttribute::Inline); - } - - if tcx.sess.must_emit_unwind_tables() { - // TODO(antoyo): emit unwind tables. - } - - let block = func.new_block("entry"); - block.end_with_return(None, value); -} - fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, From 1c89fe9d6d8e72c12ad78413465beb8470eca972 Mon Sep 17 00:00:00 2001 From: AudaciousAxiom <179637270+AudaciousAxiom@users.noreply.github.com> Date: Sat, 29 Nov 2025 10:19:56 +0100 Subject: [PATCH 07/23] Remove an unnecessary `unwrap` in `rustc_codegen_gcc` --- src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index c0519f7a68e28..1787415b72e6d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -503,9 +503,9 @@ fn set_rvalue_location<'a, 'gcc, 'tcx>( bx: &mut Builder<'a, 'gcc, 'tcx>, rvalue: RValue<'gcc>, ) -> RValue<'gcc> { - if bx.location.is_some() { + if let Some(location) = bx.location { #[cfg(feature = "master")] - rvalue.set_location(bx.location.unwrap()); + rvalue.set_location(location); } rvalue } From 5c467cb4d17359960c4a8c4843977012e828b48f Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Wed, 3 Dec 2025 11:15:20 -0600 Subject: [PATCH 08/23] Allow PowerPC spe_acc as clobber-only register This register is only supported on the *powerpc*spe targets. It is only recognized by LLVM. gcc does not accept this as a clobber, nor does it support these targets. This is a volatile register, thus it is included with clobber_abi. --- src/asm.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/asm.rs b/src/asm.rs index f237861b1595a..ceb3dd3ffedfc 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -209,10 +209,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } ("r", dummy_output_type(self.cx, reg.reg_class())) } else { - // `clobber_abi` can add lots of clobbers that are not supported by the target, - // such as AVX-512 registers, so we just ignore unsupported registers - let is_target_supported = - reg.reg_class().supported_types(asm_arch, true).iter().any( + let is_target_supported = match reg.reg_class() { + // `clobber_abi` clobbers spe_acc on all PowerPC targets. This + // register is unique to the powerpc*spe target, and the target + // is not supported by gcc. Ignore it. + InlineAsmRegClass::PowerPC( + PowerPCInlineAsmRegClass::spe_acc, + ) => false, + // `clobber_abi` can add lots of clobbers that are not supported by the target, + // such as AVX-512 registers, so we just ignore unsupported registers + x => x.supported_types(asm_arch, true).iter().any( |&(_, feature)| { if let Some(feature) = feature { self.tcx @@ -222,7 +228,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { true // Register class is unconditionally supported } }, - ); + ), + }; if is_target_supported && !clobbers.contains(®_name) { clobbers.push(reg_name); @@ -710,7 +717,8 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } @@ -793,7 +801,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl PowerPCInlineAsmRegClass::cr | PowerPCInlineAsmRegClass::ctr | PowerPCInlineAsmRegClass::lr - | PowerPCInlineAsmRegClass::xer, + | PowerPCInlineAsmRegClass::xer + | PowerPCInlineAsmRegClass::spe_acc, ) => { unreachable!("clobber-only") } From 701b9ba0fbaa79bb359a6e4e0377e671b2ffba92 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 14:53:08 +0100 Subject: [PATCH 09/23] Merge commit 'dab6863ce82346cf56c88b6f90a146200358207f' into subtree-update_cg_gcc_2025-12-04 --- CONTRIBUTING.md | 37 ++++ Cargo.lock | 4 +- build_system/src/build.rs | 12 +- build_system/src/config.rs | 7 +- build_system/src/test.rs | 6 - src/int.rs | 48 +---- src/intrinsic/mod.rs | 378 ++++++++++++++++-------------------- src/lib.rs | 20 +- tests/lang_tests_common.rs | 14 +- tests/run/int_intrinsics.rs | 72 +++++++ 10 files changed, 322 insertions(+), 276 deletions(-) create mode 100644 tests/run/int_intrinsics.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54cba0e6de379..8f81ecca445a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,43 @@ We encourage new contributors to join our communication channels and introduce t ## Understanding Core Concepts +### Sysroot & compilation flags + +#### What *is* the sysroot? +The **sysroot** is the directory that stores the compiled standard +library (`core`, `alloc`, `std`, `test`, …) and compiler built-ins. +Rustup ships these libraries **pre-compiled with LLVM**. + +**rustc_codegen_gcc** replaces LLVM with the GCC backend. + +The freshly compiled sysroot ends up in +`build/build_sysroot/...`. + +A rebuild of sysroot is needed when + +* the backend changes in a way that affects code generation, or +* the user switches toolchains / updates submodules. + +Both backend and sysroot can be built using different [profiles](https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles). +That is exactly what the `--sysroot`, `--release-sysroot` and `--release` flag supported by the build system script `y.sh` take care of. + + +#### Typical flag combinations + +| Command | Backend Profile | Sysroot Profile | Usage Scenario | +|--------------------------------------------|-------------------------------|----------------------------------|------------------------------------------------------------| +| `./y.sh build` |  dev* |  n/a |  Build backend in dev mode with optimized dependencies without rebuilding sysroot | +| `./y.sh build --release` |  release (optimized) |  n/a |  Build backend in release mode with optimized dependencies without rebuilding sysroot | +| `./y.sh build --release --sysroot` |  release (optimized) |  dev |  Build backend in release mode with optimized dependencies and sysroot in dev mode (unoptimized) | +| `./y.sh build --sysroot` |  dev* |  dev |  Build backend in dev mode with optimized dependencies and sysroot in dev mode (unoptimized) | +| `./y.sh build --release-sysroot --sysroot`|  dev* |  release (optimized) |  Build backend in dev mode and sysroot in release mode, both with optimized dependencies | + +\* In `dev` mode, dependencies are compiled with optimizations, while the code of the backend itself is not. + + +Note: `--release-sysroot` must be used together with `--sysroot`. + + ### Common Development Tasks #### Running Specific Tests diff --git a/Cargo.lock b/Cargo.lock index 00bdacaca6762..dea1207b05da8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "gccjit_sys" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "263da4f60b7bb5d6a5b21efda961741051ebdbf0e380a09118b03cce66a8c77e" +checksum = "4f81d901767ddba371a619fa9bba657066a4d3c5607ee69bbb557c1c5ba9bf85" dependencies = [ "libc", ] diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 56503b239a3b5..27476465d740d 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -46,8 +46,16 @@ impl BuildArg { println!( r#" `build` command help: - - --sysroot : Build with sysroot"# + --sysroot : When used on its own, build backend in dev mode with optimized dependencies + and sysroot in dev mode (unoptimized) + When used together with --release, build backend in release mode with optimized dependencies + When used together with --release-sysroot, + build the sysroot in release mode with optimized dependencies instead of in dev mode + --release-sysroot : When combined with --sysroot, additionally + build the sysroot in release mode with optimized dependencies. + It has no effect if `--sysroot` is not specified. + It should not be used on its own. + --sysroot-panic-abort : Build the sysroot without unwinding support"# ); ConfigInfo::show_usage(); println!(" --help : Show this help"); diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 19255e1ba2b2c..8eb6d8f019e1c 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -459,14 +459,11 @@ impl ConfigInfo { pub fn show_usage() { println!( - "\ - --features [arg] : Add a new feature [arg] + " --features [arg] : Add a new feature [arg] --target-triple [arg] : Set the target triple to [arg] --target [arg] : Set the target to [arg] + --release : Build backend in release mode with optimized dependencies --out-dir : Location where the files will be generated - --release : Build in release mode - --release-sysroot : Build sysroot in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support --config-file : Location of the config file to be used --gcc-path : Location of the GCC root folder --cg_gcc-path : Location of the rustc_codegen_gcc root folder (used diff --git a/build_system/src/test.rs b/build_system/src/test.rs index 8aabfa894ce08..ca2a2a7dc2de0 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -64,8 +64,6 @@ fn show_usage() { r#" `test` command help: - --release : Build codegen in release mode - --sysroot-panic-abort : Build the sysroot without unwinding support. --features [arg] : Add a new feature [arg] --use-system-gcc : Use system installed libgccjit --build-only : Only build rustc_codegen_gcc then exits @@ -92,7 +90,6 @@ struct TestArg { test_args: Vec, nb_parts: Option, current_part: Option, - sysroot_panic_abort: bool, config_info: ConfigInfo, sysroot_features: Vec, keep_lto_tests: bool, @@ -128,9 +125,6 @@ impl TestArg { test_arg.current_part = Some(get_number_after_arg(&mut args, "--current-part")?); } - "--sysroot-panic-abort" => { - test_arg.sysroot_panic_abort = true; - } "--keep-lto-tests" => { test_arg.keep_lto_tests = true; } diff --git a/src/int.rs b/src/int.rs index aa1d3b6b091c6..49de0b490e88d 100644 --- a/src/int.rs +++ b/src/int.rs @@ -287,51 +287,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): remove duplication with intrinsic? let name = if self.is_native_int_type(lhs.get_type()) { match oop { - OverflowOp::Add => match new_kind { - Int(I8) => "__builtin_add_overflow", - Int(I16) => "__builtin_add_overflow", - Int(I32) => "__builtin_sadd_overflow", - Int(I64) => "__builtin_saddll_overflow", - Int(I128) => "__builtin_add_overflow", - - Uint(U8) => "__builtin_add_overflow", - Uint(U16) => "__builtin_add_overflow", - Uint(U32) => "__builtin_uadd_overflow", - Uint(U64) => "__builtin_uaddll_overflow", - Uint(U128) => "__builtin_add_overflow", - - _ => unreachable!(), - }, - OverflowOp::Sub => match new_kind { - Int(I8) => "__builtin_sub_overflow", - Int(I16) => "__builtin_sub_overflow", - Int(I32) => "__builtin_ssub_overflow", - Int(I64) => "__builtin_ssubll_overflow", - Int(I128) => "__builtin_sub_overflow", - - Uint(U8) => "__builtin_sub_overflow", - Uint(U16) => "__builtin_sub_overflow", - Uint(U32) => "__builtin_usub_overflow", - Uint(U64) => "__builtin_usubll_overflow", - Uint(U128) => "__builtin_sub_overflow", - - _ => unreachable!(), - }, - OverflowOp::Mul => match new_kind { - Int(I8) => "__builtin_mul_overflow", - Int(I16) => "__builtin_mul_overflow", - Int(I32) => "__builtin_smul_overflow", - Int(I64) => "__builtin_smulll_overflow", - Int(I128) => "__builtin_mul_overflow", - - Uint(U8) => "__builtin_mul_overflow", - Uint(U16) => "__builtin_mul_overflow", - Uint(U32) => "__builtin_umul_overflow", - Uint(U64) => "__builtin_umulll_overflow", - Uint(U128) => "__builtin_mul_overflow", - - _ => unreachable!(), - }, + OverflowOp::Add => "__builtin_add_overflow", + OverflowOp::Sub => "__builtin_sub_overflow", + OverflowOp::Mul => "__builtin_mul_overflow", } } else { let (func_name, width) = match oop { diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 8225df5686417..23d16eda030c1 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -441,43 +441,15 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc | sym::saturating_sub => { match int_type_width_signed(args[0].layout.ty, self) { Some((width, signed)) => match name { - sym::ctlz | sym::cttz => { - let func = self.current_func(); - let then_block = func.new_block("then"); - let else_block = func.new_block("else"); - let after_block = func.new_block("after"); - - let arg = args[0].immediate(); - let result = func.new_local(None, self.u32_type, "zeros"); - let zero = self.cx.gcc_zero(arg.get_type()); - let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); - self.llbb().end_with_conditional(None, cond, then_block, else_block); - - let zero_result = self.cx.gcc_uint(self.u32_type, width); - then_block.add_assignment(None, result, zero_result); - then_block.end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place - // count_leading_zeroes() does not expect, the current block - // in the state need to be updated. - self.switch_to_block(else_block); - - let zeros = match name { - sym::ctlz => self.count_leading_zeroes(width, arg), - sym::cttz => self.count_trailing_zeroes(width, arg), - _ => unreachable!(), - }; - self.llbb().add_assignment(None, result, zeros); - self.llbb().end_with_jump(None, after_block); - - // NOTE: since jumps were added in a place rustc does not - // expect, the current block in the state need to be updated. - self.switch_to_block(after_block); - - result.to_rvalue() + sym::ctlz => self.count_leading_zeroes(width, args[0].immediate()), + + sym::ctlz_nonzero => { + self.count_leading_zeroes_nonzero(width, args[0].immediate()) + } + sym::cttz => self.count_trailing_zeroes(width, args[0].immediate()), + sym::cttz_nonzero => { + self.count_trailing_zeroes_nonzero(width, args[0].immediate()) } - sym::ctlz_nonzero => self.count_leading_zeroes(width, args[0].immediate()), - sym::cttz_nonzero => self.count_trailing_zeroes(width, args[0].immediate()), sym::ctpop => self.pop_count(args[0].immediate()), sym::bswap => { if width == 8 { @@ -912,179 +884,175 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.gcc_int_cast(result, result_type) } - fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): use width? - let arg_type = arg.get_type(); - let result_type = self.u32_type; - let arg = if arg_type.is_signed(self.cx) { - let new_type = arg_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, new_type) + fn count_zeroes(&mut self, width: u64, arg: RValue<'gcc>, count_leading: bool) -> RValue<'gcc> { + // if arg is 0, early return 0, else call count_leading_zeroes_nonzero or count_trailing_zeroes_nonzero + let func = self.current_func(); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let result = func.new_local(None, self.u32_type, "zeros"); + let zero = self.cx.gcc_zero(arg.get_type()); + let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.gcc_uint(self.u32_type, width); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place count_xxxxing_zeroes_nonzero() does not expect, + // the current block in the state need to be updated. + self.switch_to_block(else_block); + + let zeros = if count_leading { + self.count_leading_zeroes_nonzero(width, arg) } else { - arg + self.count_trailing_zeroes_nonzero(width, arg) }; - let arg_type = arg.get_type(); - let count_leading_zeroes = - // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here - // instead of using is_uint(). - if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { - "__builtin_clz" - } - else if arg_type.is_ulong(self.cx) { - "__builtin_clzl" - } - else if arg_type.is_ulonglong(self.cx) { - "__builtin_clzll" - } - else if width == 128 { - // Algorithm from: https://stackoverflow.com/a/28433850/389119 - let array_type = self.context.new_array_type(None, arg_type, 3); - let result = self.current_func() - .new_local(None, array_type, "count_loading_zeroes_results"); - - let sixty_four = self.const_uint(arg_type, 64); - let shift = self.lshr(arg, sixty_four); - let high = self.gcc_int_cast(shift, self.u64_type); - let low = self.gcc_int_cast(arg, self.u64_type); - - let zero = self.context.new_rvalue_zero(self.usize_type); - let one = self.context.new_rvalue_one(self.usize_type); - let two = self.context.new_rvalue_from_long(self.usize_type, 2); - - let clzll = self.context.get_builtin_function("__builtin_clzll"); - - let first_elem = self.context.new_array_access(None, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type); - self.llbb() - .add_assignment(self.location, first_elem, first_value); - - let second_elem = self.context.new_array_access(self.location, result, one); - let cast = self.gcc_int_cast(self.context.new_call(self.location, clzll, &[low]), arg_type); - let second_value = self.add(cast, sixty_four); - self.llbb() - .add_assignment(self.location, second_elem, second_value); - - let third_elem = self.context.new_array_access(self.location, result, two); - let third_value = self.const_uint(arg_type, 128); - self.llbb() - .add_assignment(self.location, third_elem, third_value); - - let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); - let not_low_and_not_high = not_low & not_high; - let index = not_high + not_low_and_not_high; - // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in - // gcc. - // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the - // compilation stage. - let index = self.context.new_cast(self.location, index, self.i32_type); - - let res = self.context.new_array_access(self.location, result, index); - - return self.gcc_int_cast(res.to_rvalue(), result_type); - } - else { - let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); - let arg = self.context.new_cast(self.location, arg, self.ulonglong_type); - let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; - let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8); - let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]) - diff; - return self.context.new_cast(self.location, res, result_type); - }; - let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); - let res = self.context.new_call(self.location, count_leading_zeroes, &[arg]); - self.context.new_cast(self.location, res, result_type) + self.llbb().add_assignment(None, result, zeros); + self.llbb().end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current block in the state need to be updated. + self.switch_to_block(after_block); + + result.to_rvalue() } - fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { - let arg_type = arg.get_type(); + fn count_zeroes_nonzero( + &mut self, + width: u64, + arg: RValue<'gcc>, + count_leading: bool, + ) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller + fn use_builtin_function<'a, 'gcc, 'tcx>( + builder: &mut Builder<'a, 'gcc, 'tcx>, + builtin: &str, + arg: RValue<'gcc>, + arg_type: gccjit::Type<'gcc>, + expected_type: gccjit::Type<'gcc>, + ) -> RValue<'gcc> { + let arg = if arg_type != expected_type { + builder.context.new_cast(builder.location, arg, expected_type) + } else { + arg + }; + let builtin = builder.context.get_builtin_function(builtin); + let res = builder.context.new_call(builder.location, builtin, &[arg]); + builder.context.new_cast(builder.location, res, builder.u32_type) + } + + // TODO(antoyo): use width? let result_type = self.u32_type; + let mut arg_type = arg.get_type(); let arg = if arg_type.is_signed(self.cx) { - let new_type = arg_type.to_unsigned(self.cx); - self.gcc_int_cast(arg, new_type) + arg_type = arg_type.to_unsigned(self.cx); + self.gcc_int_cast(arg, arg_type) } else { arg }; - let arg_type = arg.get_type(); - let (count_trailing_zeroes, expected_type) = - // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here - // instead of using is_uint(). - if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { - // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero. - ("__builtin_ctz", self.cx.uint_type) - } - else if arg_type.is_ulong(self.cx) { - ("__builtin_ctzl", self.cx.ulong_type) - } - else if arg_type.is_ulonglong(self.cx) { - ("__builtin_ctzll", self.cx.ulonglong_type) - } - else if arg_type.is_u128(self.cx) { - // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119 - let array_type = self.context.new_array_type(None, arg_type, 3); - let result = self.current_func() - .new_local(None, array_type, "count_loading_zeroes_results"); - - let sixty_four = self.gcc_int(arg_type, 64); - let shift = self.gcc_lshr(arg, sixty_four); - let high = self.gcc_int_cast(shift, self.u64_type); - let low = self.gcc_int_cast(arg, self.u64_type); - - let zero = self.context.new_rvalue_zero(self.usize_type); - let one = self.context.new_rvalue_one(self.usize_type); - let two = self.context.new_rvalue_from_long(self.usize_type, 2); - - let ctzll = self.context.get_builtin_function("__builtin_ctzll"); - - let first_elem = self.context.new_array_access(self.location, result, zero); - let first_value = self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[low]), arg_type); - self.llbb() - .add_assignment(self.location, first_elem, first_value); - - let second_elem = self.context.new_array_access(self.location, result, one); - let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(self.location, ctzll, &[high]), arg_type), sixty_four); - self.llbb() - .add_assignment(self.location, second_elem, second_value); - - let third_elem = self.context.new_array_access(self.location, result, two); - let third_value = self.gcc_int(arg_type, 128); - self.llbb() - .add_assignment(self.location, third_elem, third_value); - - let not_low = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, low); - let not_high = self.context.new_unary_op(self.location, UnaryOp::LogicalNegate, self.u64_type, high); - let not_low_and_not_high = not_low & not_high; - let index = not_low + not_low_and_not_high; - // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in - // gcc. - // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the - // compilation stage. - let index = self.context.new_cast(self.location, index, self.i32_type); - - let res = self.context.new_array_access(self.location, result, index); - - return self.gcc_int_cast(res.to_rvalue(), result_type); - } - else { + // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here + // instead of using is_uint(). + if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) { + let builtin = if count_leading { "__builtin_clz" } else { "__builtin_ctz" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if arg_type.is_ulong(self.cx) { + let builtin = if count_leading { "__builtin_clzl" } else { "__builtin_ctzl" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if arg_type.is_ulonglong(self.cx) { + let builtin = if count_leading { "__builtin_clzll" } else { "__builtin_ctzll" }; + use_builtin_function(self, builtin, arg, arg_type, self.cx.uint_type) + } else if width == 128 { + // arg is guaranteed to not be 0, so either its 64 high or 64 low bits are not 0 + // __buildin_clzll is UB when called with 0, so call it on the 64 high bits if they are not 0, + // else call it on the 64 low bits and add 64. In the else case, 64 low bits can't be 0 + // because arg is not 0. + // __buildin_ctzll is UB when called with 0, so call it on the 64 low bits if they are not 0, + // else call it on the 64 high bits and add 64. In the else case, 64 high bits can't be 0 + // because arg is not 0. + + let result = self.current_func().new_local(None, result_type, "count_zeroes_results"); + + let cz_then_block = self.current_func().new_block("cz_then"); + let cz_else_block = self.current_func().new_block("cz_else"); + let cz_after_block = self.current_func().new_block("cz_after"); + + let low = self.gcc_int_cast(arg, self.u64_type); + let sixty_four = self.const_uint(arg_type, 64); + let shift = self.lshr(arg, sixty_four); + let high = self.gcc_int_cast(shift, self.u64_type); + + let (first, second, builtin) = if count_leading { + (low, high, self.context.get_builtin_function("__builtin_clzll")) + } else { + (high, low, self.context.get_builtin_function("__builtin_ctzll")) + }; + + let zero_64 = self.const_uint(self.u64_type, 0); + let cond = self.gcc_icmp(IntPredicate::IntNE, second, zero_64); + self.llbb().end_with_conditional(self.location, cond, cz_then_block, cz_else_block); + self.switch_to_block(cz_then_block); + + let result_128 = + self.gcc_int_cast(self.context.new_call(None, builtin, &[second]), result_type); + + cz_then_block.add_assignment(self.location, result, result_128); + cz_then_block.end_with_jump(self.location, cz_after_block); + + self.switch_to_block(cz_else_block); + let count_more_zeroes = + self.gcc_int_cast(self.context.new_call(None, builtin, &[first]), result_type); + let sixty_four_result_type = self.const_uint(result_type, 64); + let count_result_type = self.add(count_more_zeroes, sixty_four_result_type); + cz_else_block.add_assignment(self.location, result, count_result_type); + cz_else_block.end_with_jump(self.location, cz_after_block); + self.switch_to_block(cz_after_block); + result.to_rvalue() + } else { + let byte_diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64; + let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); + let ull_arg = self.context.new_cast(self.location, arg, self.ulonglong_type); + + let res = if count_leading { + let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll"); + self.context.new_call(self.location, count_leading_zeroes, &[ull_arg]) - diff + } else { let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll"); - let arg_size = arg_type.get_size(); - let casted_arg = self.context.new_cast(self.location, arg, self.ulonglong_type); - let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64; - let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8); let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set. - let masked = mask & self.context.new_unary_op(self.location, UnaryOp::BitwiseNegate, arg_type, arg); - let cond = self.context.new_comparison(self.location, ComparisonOp::Equals, masked, mask); + let masked = mask + & self.context.new_unary_op( + self.location, + UnaryOp::BitwiseNegate, + arg_type, + arg, + ); + let cond = + self.context.new_comparison(self.location, ComparisonOp::Equals, masked, mask); let diff = diff * self.context.new_cast(self.location, cond, self.int_type); - let res = self.context.new_call(self.location, count_trailing_zeroes, &[casted_arg]) - diff; - return self.context.new_cast(self.location, res, result_type); + + self.context.new_call(self.location, count_trailing_zeroes, &[ull_arg]) - diff }; - let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); - let arg = if arg_type != expected_type { - self.context.new_cast(self.location, arg, expected_type) - } else { - arg - }; - let res = self.context.new_call(self.location, count_trailing_zeroes, &[arg]); - self.context.new_cast(self.location, res, result_type) + self.context.new_cast(self.location, res, result_type) + } + } + + fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + self.count_zeroes(width, arg, true) + } + + fn count_leading_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller, else count_leading_zeros should be used + self.count_zeroes_nonzero(width, arg, true) + } + + fn count_trailing_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + self.count_zeroes(width, arg, false) + } + + fn count_trailing_zeroes_nonzero(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // Pre-condition: arg is guaranteed to not be 0 by caller, else count_trailing_zeros should be used + self.count_zeroes_nonzero(width, arg, false) } fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> { @@ -1196,14 +1164,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let res = func.new_local(self.location, result_type, "saturating_sum"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { - let func_name = match width { - 8 => "__builtin_add_overflow", - 16 => "__builtin_add_overflow", - 32 => "__builtin_sadd_overflow", - 64 => "__builtin_saddll_overflow", - 128 => "__builtin_add_overflow", - _ => unreachable!(), - }; + let func_name = "__builtin_add_overflow"; let overflow_func = self.context.get_builtin_function(func_name); self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) } else { @@ -1267,14 +1228,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let res = func.new_local(self.location, result_type, "saturating_diff"); let supports_native_type = self.is_native_int_type(result_type); let overflow = if supports_native_type { - let func_name = match width { - 8 => "__builtin_sub_overflow", - 16 => "__builtin_sub_overflow", - 32 => "__builtin_ssub_overflow", - 64 => "__builtin_ssubll_overflow", - 128 => "__builtin_sub_overflow", - _ => unreachable!(), - }; + let func_name = "__builtin_sub_overflow"; let overflow_func = self.context.get_builtin_function(func_name); self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(self.location)], None) } else { diff --git a/src/lib.rs b/src/lib.rs index 662e303f94f2d..c1506ee6176f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,7 @@ mod type_of; use std::any::Any; use std::ffi::CString; use std::fmt::Debug; +use std::fs; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -180,14 +181,18 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); +fn libgccjit_path(sysroot_path: &Path) -> PathBuf { + let sysroot_lib_dir = sysroot_path.join("lib"); + sysroot_lib_dir.join("libgccjit.so") +} + fn load_libgccjit_if_needed(sysroot_path: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let sysroot_lib_dir = sysroot_path.join("lib"); - let libgccjit_target_lib_file = sysroot_lib_dir.join("libgccjit.so"); + let libgccjit_target_lib_file = libgccjit_path(sysroot_path); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -207,7 +212,16 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { - load_libgccjit_if_needed(sess.opts.sysroot.path()); + // We use all_paths() instead of only path() in case the path specified by --sysroot is + // invalid. + // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. + for path in sess.opts.sysroot.all_paths() { + let libgccjit_target_lib_file = libgccjit_path(path); + if let Ok(true) = fs::exists(libgccjit_target_lib_file) { + load_libgccjit_if_needed(path); + break; + } + } #[cfg(feature = "master")] { diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 311f256b76008..0f2cb9231062a 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -91,7 +91,19 @@ pub fn main_inner(profile: Profile) { } } match profile { - Profile::Debug => {} + Profile::Debug => { + if test_target.is_ok() { + // m68k doesn't have lubsan for now + compiler.args(["-C", "llvm-args=sanitize-undefined"]); + } else { + compiler.args([ + "-C", + "llvm-args=sanitize-undefined", + "-C", + "link-args=-lubsan", + ]); + } + } Profile::Release => { compiler.args(["-C", "opt-level=3", "-C", "lto=no"]); } diff --git a/tests/run/int_intrinsics.rs b/tests/run/int_intrinsics.rs new file mode 100644 index 0000000000000..c3d363c8428ba --- /dev/null +++ b/tests/run/int_intrinsics.rs @@ -0,0 +1,72 @@ +// Compiler: +// +// Run-time: +#![feature(core_intrinsics, intrinsics)] +#![no_main] + +use std::intrinsics::black_box; + +#[rustc_intrinsic] +pub const fn ctlz(_x: T) -> u32; + +#[rustc_intrinsic] +pub const fn cttz(_x: T) -> u32; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + macro_rules! check { + ($func_name:ident, $input:expr, $expected:expr, $res_ident:ident) => {{ + $res_ident += 1; + if $func_name(black_box($input)) != $expected { + return $res_ident; + } + }}; + } + let mut res = 0; + check!(ctlz, 0_u128, 128_u32, res); + check!(ctlz, 1_u128, 127_u32, res); + check!(ctlz, 0x4000_0000_0000_0000_0000_0000_0000_0000_u128, 1_u32, res); + check!(ctlz, 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, 0_u32, res); + check!(cttz, 0_u128, 128_u32, res); + check!(cttz, 1_u128, 0_u32, res); + check!(cttz, 2_u128, 1_u32, res); + check!(cttz, 0x8000_0000_0000_0000_0000_0000_0000_0000_u128, 127_u32, res); + + check!(ctlz, 0_u64, 64_u32, res); + check!(ctlz, 1_u64, 63_u32, res); + check!(ctlz, 0x4000_0000_0000_0000_u64, 1_u32, res); + check!(ctlz, 0x8000_0000_0000_0000_u64, 0_u32, res); + check!(cttz, 0_u64, 64_u32, res); + check!(cttz, 1_u64, 0_u32, res); + check!(cttz, 2_u64, 1_u32, res); + check!(cttz, 0x8000_0000_0000_0000_u64, 63_u32, res); + + check!(ctlz, 0_u32, 32_u32, res); + check!(ctlz, 1_u32, 31_u32, res); + check!(ctlz, 0x4000_0000_u32, 1_u32, res); + check!(ctlz, 0x8000_0000_u32, 0_u32, res); + check!(cttz, 0_u32, 32_u32, res); + check!(cttz, 1_u32, 0_u32, res); + check!(cttz, 2_u32, 1_u32, res); + check!(cttz, 0x8000_0000_u32, 31_u32, res); + + check!(ctlz, 0_u16, 16_u32, res); + check!(ctlz, 1_u16, 15_u32, res); + check!(ctlz, 0x4000_u16, 1_u32, res); + check!(ctlz, 0x8000_u16, 0_u32, res); + check!(cttz, 0_u16, 16_u32, res); + check!(cttz, 1_u16, 0_u32, res); + check!(cttz, 2_u16, 1_u32, res); + check!(cttz, 0x8000_u16, 15_u32, res); + + check!(ctlz, 0_u8, 8_u32, res); + check!(ctlz, 1_u8, 7_u32, res); + check!(ctlz, 0x40_u8, 1_u32, res); + check!(ctlz, 0x80_u8, 0_u32, res); + check!(cttz, 0_u8, 8_u32, res); + check!(cttz, 1_u8, 0_u32, res); + check!(cttz, 2_u8, 1_u32, res); + check!(cttz, 0x80_u8, 7_u32, res); + + 0 +} From 897099e693c52c90baa7f3c5897668b0577f69de Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 4 Dec 2025 17:53:01 +0100 Subject: [PATCH 10/23] Regenerate intrinsics --- src/intrinsic/archs.rs | 123 +++++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 24 deletions(-) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index bb8bcbf66f380..43e7c352c34a3 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -70,10 +70,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "sve.sm4e" => "__builtin_sve_svsm4e_u32", "sve.sm4ekey" => "__builtin_sve_svsm4ekey_u32", "sve.wrffr" => "__builtin_sve_svwrffr", - "tcancel" => "__builtin_arm_tcancel", - "tcommit" => "__builtin_arm_tcommit", - "tstart" => "__builtin_arm_tstart", - "ttest" => "__builtin_arm_ttest", _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } @@ -1632,6 +1628,14 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.vabs.f8.128B" => "__builtin_HEXAGON_V6_vabs_f8_128B", "V6.vabs.hf" => "__builtin_HEXAGON_V6_vabs_hf", "V6.vabs.hf.128B" => "__builtin_HEXAGON_V6_vabs_hf_128B", + "V6.vabs.qf16.hf" => "__builtin_HEXAGON_V6_vabs_qf16_hf", + "V6.vabs.qf16.hf.128B" => "__builtin_HEXAGON_V6_vabs_qf16_hf_128B", + "V6.vabs.qf16.qf16" => "__builtin_HEXAGON_V6_vabs_qf16_qf16", + "V6.vabs.qf16.qf16.128B" => "__builtin_HEXAGON_V6_vabs_qf16_qf16_128B", + "V6.vabs.qf32.qf32" => "__builtin_HEXAGON_V6_vabs_qf32_qf32", + "V6.vabs.qf32.qf32.128B" => "__builtin_HEXAGON_V6_vabs_qf32_qf32_128B", + "V6.vabs.qf32.sf" => "__builtin_HEXAGON_V6_vabs_qf32_sf", + "V6.vabs.qf32.sf.128B" => "__builtin_HEXAGON_V6_vabs_qf32_sf_128B", "V6.vabs.sf" => "__builtin_HEXAGON_V6_vabs_sf", "V6.vabs.sf.128B" => "__builtin_HEXAGON_V6_vabs_sf_128B", "V6.vabsb" => "__builtin_HEXAGON_V6_vabsb", @@ -1744,6 +1748,8 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.vaddwsat.128B" => "__builtin_HEXAGON_V6_vaddwsat_128B", "V6.vaddwsat.dv" => "__builtin_HEXAGON_V6_vaddwsat_dv", "V6.vaddwsat.dv.128B" => "__builtin_HEXAGON_V6_vaddwsat_dv_128B", + "V6.valign4" => "__builtin_HEXAGON_V6_valign4", + "V6.valign4.128B" => "__builtin_HEXAGON_V6_valign4_128B", "V6.valignb" => "__builtin_HEXAGON_V6_valignb", "V6.valignb.128B" => "__builtin_HEXAGON_V6_valignb_128B", "V6.valignbi" => "__builtin_HEXAGON_V6_valignbi", @@ -1862,14 +1868,30 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.vcl0w.128B" => "__builtin_HEXAGON_V6_vcl0w_128B", "V6.vcombine" => "__builtin_HEXAGON_V6_vcombine", "V6.vcombine.128B" => "__builtin_HEXAGON_V6_vcombine_128B", + "V6.vconv.bf.qf32" => "__builtin_HEXAGON_V6_vconv_bf_qf32", + "V6.vconv.bf.qf32.128B" => "__builtin_HEXAGON_V6_vconv_bf_qf32_128B", + "V6.vconv.f8.qf16" => "__builtin_HEXAGON_V6_vconv_f8_qf16", + "V6.vconv.f8.qf16.128B" => "__builtin_HEXAGON_V6_vconv_f8_qf16_128B", "V6.vconv.h.hf" => "__builtin_HEXAGON_V6_vconv_h_hf", "V6.vconv.h.hf.128B" => "__builtin_HEXAGON_V6_vconv_h_hf_128B", + "V6.vconv.h.hf.rnd" => "__builtin_HEXAGON_V6_vconv_h_hf_rnd", + "V6.vconv.h.hf.rnd.128B" => "__builtin_HEXAGON_V6_vconv_h_hf_rnd_128B", "V6.vconv.hf.h" => "__builtin_HEXAGON_V6_vconv_hf_h", "V6.vconv.hf.h.128B" => "__builtin_HEXAGON_V6_vconv_hf_h_128B", "V6.vconv.hf.qf16" => "__builtin_HEXAGON_V6_vconv_hf_qf16", "V6.vconv.hf.qf16.128B" => "__builtin_HEXAGON_V6_vconv_hf_qf16_128B", "V6.vconv.hf.qf32" => "__builtin_HEXAGON_V6_vconv_hf_qf32", "V6.vconv.hf.qf32.128B" => "__builtin_HEXAGON_V6_vconv_hf_qf32_128B", + "V6.vconv.qf16.f8" => "__builtin_HEXAGON_V6_vconv_qf16_f8", + "V6.vconv.qf16.f8.128B" => "__builtin_HEXAGON_V6_vconv_qf16_f8_128B", + "V6.vconv.qf16.hf" => "__builtin_HEXAGON_V6_vconv_qf16_hf", + "V6.vconv.qf16.hf.128B" => "__builtin_HEXAGON_V6_vconv_qf16_hf_128B", + "V6.vconv.qf16.qf16" => "__builtin_HEXAGON_V6_vconv_qf16_qf16", + "V6.vconv.qf16.qf16.128B" => "__builtin_HEXAGON_V6_vconv_qf16_qf16_128B", + "V6.vconv.qf32.qf32" => "__builtin_HEXAGON_V6_vconv_qf32_qf32", + "V6.vconv.qf32.qf32.128B" => "__builtin_HEXAGON_V6_vconv_qf32_qf32_128B", + "V6.vconv.qf32.sf" => "__builtin_HEXAGON_V6_vconv_qf32_sf", + "V6.vconv.qf32.sf.128B" => "__builtin_HEXAGON_V6_vconv_qf32_sf_128B", "V6.vconv.sf.qf32" => "__builtin_HEXAGON_V6_vconv_sf_qf32", "V6.vconv.sf.qf32.128B" => "__builtin_HEXAGON_V6_vconv_sf_qf32_128B", "V6.vconv.sf.w" => "__builtin_HEXAGON_V6_vconv_sf_w", @@ -1984,6 +2006,22 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.veqh.or.128B" => "__builtin_HEXAGON_V6_veqh_or_128B", "V6.veqh.xor" => "__builtin_HEXAGON_V6_veqh_xor", "V6.veqh.xor.128B" => "__builtin_HEXAGON_V6_veqh_xor_128B", + "V6.veqhf" => "__builtin_HEXAGON_V6_veqhf", + "V6.veqhf.128B" => "__builtin_HEXAGON_V6_veqhf_128B", + "V6.veqhf.and" => "__builtin_HEXAGON_V6_veqhf_and", + "V6.veqhf.and.128B" => "__builtin_HEXAGON_V6_veqhf_and_128B", + "V6.veqhf.or" => "__builtin_HEXAGON_V6_veqhf_or", + "V6.veqhf.or.128B" => "__builtin_HEXAGON_V6_veqhf_or_128B", + "V6.veqhf.xor" => "__builtin_HEXAGON_V6_veqhf_xor", + "V6.veqhf.xor.128B" => "__builtin_HEXAGON_V6_veqhf_xor_128B", + "V6.veqsf" => "__builtin_HEXAGON_V6_veqsf", + "V6.veqsf.128B" => "__builtin_HEXAGON_V6_veqsf_128B", + "V6.veqsf.and" => "__builtin_HEXAGON_V6_veqsf_and", + "V6.veqsf.and.128B" => "__builtin_HEXAGON_V6_veqsf_and_128B", + "V6.veqsf.or" => "__builtin_HEXAGON_V6_veqsf_or", + "V6.veqsf.or.128B" => "__builtin_HEXAGON_V6_veqsf_or_128B", + "V6.veqsf.xor" => "__builtin_HEXAGON_V6_veqsf_xor", + "V6.veqsf.xor.128B" => "__builtin_HEXAGON_V6_veqsf_xor_128B", "V6.veqw" => "__builtin_HEXAGON_V6_veqw", "V6.veqw.128B" => "__builtin_HEXAGON_V6_veqw_128B", "V6.veqw.and" => "__builtin_HEXAGON_V6_veqw_and", @@ -2096,6 +2134,14 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.vgtw.or.128B" => "__builtin_HEXAGON_V6_vgtw_or_128B", "V6.vgtw.xor" => "__builtin_HEXAGON_V6_vgtw_xor", "V6.vgtw.xor.128B" => "__builtin_HEXAGON_V6_vgtw_xor_128B", + "V6.vilog2.hf" => "__builtin_HEXAGON_V6_vilog2_hf", + "V6.vilog2.hf.128B" => "__builtin_HEXAGON_V6_vilog2_hf_128B", + "V6.vilog2.qf16" => "__builtin_HEXAGON_V6_vilog2_qf16", + "V6.vilog2.qf16.128B" => "__builtin_HEXAGON_V6_vilog2_qf16_128B", + "V6.vilog2.qf32" => "__builtin_HEXAGON_V6_vilog2_qf32", + "V6.vilog2.qf32.128B" => "__builtin_HEXAGON_V6_vilog2_qf32_128B", + "V6.vilog2.sf" => "__builtin_HEXAGON_V6_vilog2_sf", + "V6.vilog2.sf.128B" => "__builtin_HEXAGON_V6_vilog2_sf_128B", "V6.vinsertwr" => "__builtin_HEXAGON_V6_vinsertwr", "V6.vinsertwr.128B" => "__builtin_HEXAGON_V6_vinsertwr_128B", "V6.vlalignb" => "__builtin_HEXAGON_V6_vlalignb", @@ -2350,6 +2396,14 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "V6.vnavgub.128B" => "__builtin_HEXAGON_V6_vnavgub_128B", "V6.vnavgw" => "__builtin_HEXAGON_V6_vnavgw", "V6.vnavgw.128B" => "__builtin_HEXAGON_V6_vnavgw_128B", + "V6.vneg.qf16.hf" => "__builtin_HEXAGON_V6_vneg_qf16_hf", + "V6.vneg.qf16.hf.128B" => "__builtin_HEXAGON_V6_vneg_qf16_hf_128B", + "V6.vneg.qf16.qf16" => "__builtin_HEXAGON_V6_vneg_qf16_qf16", + "V6.vneg.qf16.qf16.128B" => "__builtin_HEXAGON_V6_vneg_qf16_qf16_128B", + "V6.vneg.qf32.qf32" => "__builtin_HEXAGON_V6_vneg_qf32_qf32", + "V6.vneg.qf32.qf32.128B" => "__builtin_HEXAGON_V6_vneg_qf32_qf32_128B", + "V6.vneg.qf32.sf" => "__builtin_HEXAGON_V6_vneg_qf32_sf", + "V6.vneg.qf32.sf.128B" => "__builtin_HEXAGON_V6_vneg_qf32_sf_128B", "V6.vnormamth" => "__builtin_HEXAGON_V6_vnormamth", "V6.vnormamth.128B" => "__builtin_HEXAGON_V6_vnormamth_128B", "V6.vnormamtw" => "__builtin_HEXAGON_V6_vnormamtw", @@ -2684,6 +2738,24 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "iocsrwr.d" => "__builtin_loongarch_iocsrwr_d", "iocsrwr.h" => "__builtin_loongarch_iocsrwr_h", "iocsrwr.w" => "__builtin_loongarch_iocsrwr_w", + "lasx.cast.128" => "__builtin_lasx_cast_128", + "lasx.cast.128.d" => "__builtin_lasx_cast_128_d", + "lasx.cast.128.s" => "__builtin_lasx_cast_128_s", + "lasx.concat.128" => "__builtin_lasx_concat_128", + "lasx.concat.128.d" => "__builtin_lasx_concat_128_d", + "lasx.concat.128.s" => "__builtin_lasx_concat_128_s", + "lasx.extract.128.hi" => "__builtin_lasx_extract_128_hi", + "lasx.extract.128.hi.d" => "__builtin_lasx_extract_128_hi_d", + "lasx.extract.128.hi.s" => "__builtin_lasx_extract_128_hi_s", + "lasx.extract.128.lo" => "__builtin_lasx_extract_128_lo", + "lasx.extract.128.lo.d" => "__builtin_lasx_extract_128_lo_d", + "lasx.extract.128.lo.s" => "__builtin_lasx_extract_128_lo_s", + "lasx.insert.128.hi" => "__builtin_lasx_insert_128_hi", + "lasx.insert.128.hi.d" => "__builtin_lasx_insert_128_hi_d", + "lasx.insert.128.hi.s" => "__builtin_lasx_insert_128_hi_s", + "lasx.insert.128.lo" => "__builtin_lasx_insert_128_lo", + "lasx.insert.128.lo.d" => "__builtin_lasx_insert_128_lo_d", + "lasx.insert.128.lo.s" => "__builtin_lasx_insert_128_lo_s", "lasx.vext2xv.d.b" => "__builtin_lasx_vext2xv_d_b", "lasx.vext2xv.d.h" => "__builtin_lasx_vext2xv_d_h", "lasx.vext2xv.d.w" => "__builtin_lasx_vext2xv_d_w", @@ -4950,8 +5022,20 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "f16x2.to.e5m2x2.rn.relu" => "__nvvm_f16x2_to_e5m2x2_rn_relu", "f2bf16.rn" => "__nvvm_f2bf16_rn", "f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", + "f2bf16.rn.relu.satfinite" => "__nvvm_f2bf16_rn_relu_satfinite", + "f2bf16.rn.satfinite" => "__nvvm_f2bf16_rn_satfinite", "f2bf16.rz" => "__nvvm_f2bf16_rz", "f2bf16.rz.relu" => "__nvvm_f2bf16_rz_relu", + "f2bf16.rz.relu.satfinite" => "__nvvm_f2bf16_rz_relu_satfinite", + "f2bf16.rz.satfinite" => "__nvvm_f2bf16_rz_satfinite", + "f2f16.rn" => "__nvvm_f2f16_rn", + "f2f16.rn.relu" => "__nvvm_f2f16_rn_relu", + "f2f16.rn.relu.satfinite" => "__nvvm_f2f16_rn_relu_satfinite", + "f2f16.rn.satfinite" => "__nvvm_f2f16_rn_satfinite", + "f2f16.rz" => "__nvvm_f2f16_rz", + "f2f16.rz.relu" => "__nvvm_f2f16_rz_relu", + "f2f16.rz.relu.satfinite" => "__nvvm_f2f16_rz_relu_satfinite", + "f2f16.rz.satfinite" => "__nvvm_f2f16_rz_satfinite", "f2h.rn" => "__nvvm_f2h_rn", "f2h.rn.ftz" => "__nvvm_f2h_rn_ftz", "f2i.rm" => "__nvvm_f2i_rm", @@ -5035,20 +5119,28 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "ff.to.ue8m0x2.rz.satfinite" => "__nvvm_ff_to_ue8m0x2_rz_satfinite", "ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", "ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", + "ff2bf16x2.rn.relu.satfinite" => "__nvvm_ff2bf16x2_rn_relu_satfinite", + "ff2bf16x2.rn.satfinite" => "__nvvm_ff2bf16x2_rn_satfinite", "ff2bf16x2.rs" => "__nvvm_ff2bf16x2_rs", "ff2bf16x2.rs.relu" => "__nvvm_ff2bf16x2_rs_relu", "ff2bf16x2.rs.relu.satfinite" => "__nvvm_ff2bf16x2_rs_relu_satfinite", "ff2bf16x2.rs.satfinite" => "__nvvm_ff2bf16x2_rs_satfinite", "ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", "ff2bf16x2.rz.relu" => "__nvvm_ff2bf16x2_rz_relu", + "ff2bf16x2.rz.relu.satfinite" => "__nvvm_ff2bf16x2_rz_relu_satfinite", + "ff2bf16x2.rz.satfinite" => "__nvvm_ff2bf16x2_rz_satfinite", "ff2f16x2.rn" => "__nvvm_ff2f16x2_rn", "ff2f16x2.rn.relu" => "__nvvm_ff2f16x2_rn_relu", + "ff2f16x2.rn.relu.satfinite" => "__nvvm_ff2f16x2_rn_relu_satfinite", + "ff2f16x2.rn.satfinite" => "__nvvm_ff2f16x2_rn_satfinite", "ff2f16x2.rs" => "__nvvm_ff2f16x2_rs", "ff2f16x2.rs.relu" => "__nvvm_ff2f16x2_rs_relu", "ff2f16x2.rs.relu.satfinite" => "__nvvm_ff2f16x2_rs_relu_satfinite", "ff2f16x2.rs.satfinite" => "__nvvm_ff2f16x2_rs_satfinite", "ff2f16x2.rz" => "__nvvm_ff2f16x2_rz", "ff2f16x2.rz.relu" => "__nvvm_ff2f16x2_rz_relu", + "ff2f16x2.rz.relu.satfinite" => "__nvvm_ff2f16x2_rz_relu_satfinite", + "ff2f16x2.rz.satfinite" => "__nvvm_ff2f16x2_rz_satfinite", "floor.d" => "__nvvm_floor_d", "floor.f" => "__nvvm_floor_f", "floor.ftz.f" => "__nvvm_floor_ftz_f", @@ -5942,6 +6034,8 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "altivec.vupklsb" => "__builtin_altivec_vupklsb", "altivec.vupklsh" => "__builtin_altivec_vupklsh", "altivec.vupklsw" => "__builtin_altivec_vupklsw", + "amo.ldat" => "__builtin_amo_ldat", + "amo.lwat" => "__builtin_amo_lwat", "bcdadd" => "__builtin_ppc_bcdadd", "bcdadd.p" => "__builtin_ppc_bcdadd_p", "bcdcopysign" => "__builtin_ppc_bcdcopysign", @@ -6202,6 +6296,7 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "vsx.xvminsp" => "__builtin_vsx_xvminsp", "vsx.xvredp" => "__builtin_vsx_xvredp", "vsx.xvresp" => "__builtin_vsx_xvresp", + "vsx.xvrlw" => "__builtin_vsx_xvrlw", "vsx.xvrsqrtedp" => "__builtin_vsx_xvrsqrtedp", "vsx.xvrsqrtesp" => "__builtin_vsx_xvrsqrtesp", "vsx.xvtdivdp" => "__builtin_vsx_xvtdivdp", @@ -10158,24 +10253,16 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "stui" => "__builtin_ia32_stui", "subborrow.u32" => "__builtin_ia32_subborrow_u32", "subborrow.u64" => "__builtin_ia32_subborrow_u64", - "t2rpntlvwz0" => "__builtin_ia32_t2rpntlvwz0", "t2rpntlvwz0rs" => "__builtin_ia32_t2rpntlvwz0rs", "t2rpntlvwz0rst1" => "__builtin_ia32_t2rpntlvwz0rst1", - "t2rpntlvwz0t1" => "__builtin_ia32_t2rpntlvwz0t1", - "t2rpntlvwz1" => "__builtin_ia32_t2rpntlvwz1", "t2rpntlvwz1rs" => "__builtin_ia32_t2rpntlvwz1rs", "t2rpntlvwz1rst1" => "__builtin_ia32_t2rpntlvwz1rst1", - "t2rpntlvwz1t1" => "__builtin_ia32_t2rpntlvwz1t1", "tbm.bextri.u32" => "__builtin_ia32_bextri_u32", "tbm.bextri.u64" => "__builtin_ia32_bextri_u64", "tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps", "tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal", "tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps", "tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal", - "tconjtcmmimfp16ps" => "__builtin_ia32_tconjtcmmimfp16ps", - "tconjtcmmimfp16ps.internal" => "__builtin_ia32_tconjtcmmimfp16ps_internal", - "tconjtfp16" => "__builtin_ia32_tconjtfp16", - "tconjtfp16.internal" => "__builtin_ia32_tconjtfp16_internal", "tcvtrowd2ps" => "__builtin_ia32_tcvtrowd2ps", "tcvtrowd2ps.internal" => "__builtin_ia32_tcvtrowd2ps_internal", "tcvtrowps2bf16h" => "__builtin_ia32_tcvtrowps2bf16h", @@ -10225,18 +10312,6 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "tmmultf32ps" => "__builtin_ia32_tmmultf32ps", "tmmultf32ps.internal" => "__builtin_ia32_tmmultf32ps_internal", "tpause" => "__builtin_ia32_tpause", - "ttcmmimfp16ps" => "__builtin_ia32_ttcmmimfp16ps", - "ttcmmimfp16ps.internal" => "__builtin_ia32_ttcmmimfp16ps_internal", - "ttcmmrlfp16ps" => "__builtin_ia32_ttcmmrlfp16ps", - "ttcmmrlfp16ps.internal" => "__builtin_ia32_ttcmmrlfp16ps_internal", - "ttdpbf16ps" => "__builtin_ia32_ttdpbf16ps", - "ttdpbf16ps.internal" => "__builtin_ia32_ttdpbf16ps_internal", - "ttdpfp16ps" => "__builtin_ia32_ttdpfp16ps", - "ttdpfp16ps.internal" => "__builtin_ia32_ttdpfp16ps_internal", - "ttmmultf32ps" => "__builtin_ia32_ttmmultf32ps", - "ttmmultf32ps.internal" => "__builtin_ia32_ttmmultf32ps_internal", - "ttransposed" => "__builtin_ia32_ttransposed", - "ttransposed.internal" => "__builtin_ia32_ttransposed_internal", "umonitor" => "__builtin_ia32_umonitor", "umwait" => "__builtin_ia32_umwait", "urdmsr" => "__builtin_ia32_urdmsr", From c0d4f5fab1104ef8b96750352917e018d0d99e04 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 28 Nov 2025 14:16:56 -0500 Subject: [PATCH 11/23] Move the libgccjit.so file in a target directory Since GCC is not multi-target, we need multiple libgccjit.so. Our solution to have a directory per target so that we can have multiple libgccjit.so. --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1506ee6176f2..1bdc62f7f29c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,18 +181,18 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); -fn libgccjit_path(sysroot_path: &Path) -> PathBuf { +fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { let sysroot_lib_dir = sysroot_path.join("lib"); - sysroot_lib_dir.join("libgccjit.so") + sysroot_lib_dir.join(target_triple).join("libgccjit.so") } -fn load_libgccjit_if_needed(sysroot_path: &Path) { +fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let libgccjit_target_lib_file = libgccjit_path(sysroot_path); + let libgccjit_target_lib_file = libgccjit_path(sysroot_path, target_triple); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -216,9 +216,9 @@ impl CodegenBackend for GccCodegenBackend { // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = libgccjit_path(path); + let libgccjit_target_lib_file = libgccjit_path(path, &sess.target.llvm_target); if let Ok(true) = fs::exists(libgccjit_target_lib_file) { - load_libgccjit_if_needed(path); + load_libgccjit_if_needed(path, &sess.target.llvm_target); break; } } From 8e77eeb0178af56928d4b8b1d18e71ac82e1e76b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 29 Nov 2025 11:09:23 -0500 Subject: [PATCH 12/23] Move to rustlib directory --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1bdc62f7f29c2..c40ee39ba6e4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,8 +182,9 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - let sysroot_lib_dir = sysroot_path.join("lib"); - sysroot_lib_dir.join(target_triple).join("libgccjit.so") + let sysroot_lib_dir = sysroot_path.join("lib").join("rustlib"); + let libgccjit_target_lib_file = + sysroot_lib_dir.join(target_triple).join("lib").join("libgccjit.so"); } fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { From b00418c0f5752f11aa2455abe927dd593957e3c7 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 29 Nov 2025 12:19:14 -0500 Subject: [PATCH 13/23] Fix lib path --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c40ee39ba6e4d..6c072e7daca20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,6 +98,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames}; +use rustc_session::filesearch::make_target_lib_path; use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tempfile::TempDir; @@ -182,9 +183,7 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - let sysroot_lib_dir = sysroot_path.join("lib").join("rustlib"); - let libgccjit_target_lib_file = - sysroot_lib_dir.join(target_triple).join("lib").join("libgccjit.so"); + make_target_lib_path(sysroot_path, target_triple).join("libgccjit.so") } fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { From ff29461e1a03d52687f81da8d9ce44f5358d5f21 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 5 Dec 2025 09:58:37 -0500 Subject: [PATCH 14/23] Remove libgccjit_path function --- src/lib.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6c072e7daca20..a77239e23b4e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,17 +182,12 @@ pub struct GccCodegenBackend { static LTO_SUPPORTED: AtomicBool = AtomicBool::new(false); -fn libgccjit_path(sysroot_path: &Path, target_triple: &str) -> PathBuf { - make_target_lib_path(sysroot_path, target_triple).join("libgccjit.so") -} - -fn load_libgccjit_if_needed(sysroot_path: &Path, target_triple: &str) { +fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. return; } - let libgccjit_target_lib_file = libgccjit_path(sysroot_path, target_triple); let path = libgccjit_target_lib_file.to_str().expect("libgccjit path"); let string = CString::new(path).expect("string to libgccjit path"); @@ -216,9 +211,10 @@ impl CodegenBackend for GccCodegenBackend { // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = libgccjit_path(path, &sess.target.llvm_target); - if let Ok(true) = fs::exists(libgccjit_target_lib_file) { - load_libgccjit_if_needed(path, &sess.target.llvm_target); + let libgccjit_target_lib_file = + make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so"); + if let Ok(true) = fs::exists(&libgccjit_target_lib_file) { + load_libgccjit_if_needed(&libgccjit_target_lib_file); break; } } From 1314419ccdec8f54da53a812322c8053774f88c9 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 8 Dec 2025 19:23:10 +0100 Subject: [PATCH 15/23] Remove `[no-mentions]` handler in our triagebot config https://github.blog/changelog/2025-11-07-removing-notifications-for-mentions-in-commit-messages/ --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 13da0a87def3c..eb0c7b011f605 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -2,6 +2,3 @@ # Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) [issue-links] - -# Prevents mentions in commits to avoid users being spammed -[no-mentions] From e6143962f9802e88018a7084ef836203c90cef45 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Dec 2025 15:42:22 +0100 Subject: [PATCH 16/23] Fix clippy lint in `cg_gcc` --- src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 1787415b72e6d..df1e64c75b963 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -500,11 +500,11 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { } fn set_rvalue_location<'a, 'gcc, 'tcx>( - bx: &mut Builder<'a, 'gcc, 'tcx>, + _bx: &mut Builder<'a, 'gcc, 'tcx>, rvalue: RValue<'gcc>, ) -> RValue<'gcc> { - if let Some(location) = bx.location { - #[cfg(feature = "master")] + #[cfg(feature = "master")] + if let Some(location) = _bx.location { rvalue.set_location(location); } rvalue From a95aaca24965ff3661fd11a8b45883ea990a29a0 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 6 Dec 2025 11:54:06 +0100 Subject: [PATCH 17/23] Adapt and fix `cg_gcc` to the overhauled filename remapping --- src/debuginfo.rs | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/debuginfo.rs b/src/debuginfo.rs index 3979f62987f2c..53d3670c15248 100644 --- a/src/debuginfo.rs +++ b/src/debuginfo.rs @@ -297,29 +297,11 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let pos = span.lo(); let DebugLoc { file, line, col } = self.lookup_debug_loc(pos); match file.name { - rustc_span::FileName::Real(ref name) => match *name { - rustc_span::RealFileName::LocalPath(ref name) => { - if let Some(name) = name.to_str() { - self.context.new_location(name, line as i32, col as i32) - } else { - Location::null() - } - } - rustc_span::RealFileName::Remapped { - ref local_path, - virtual_name: ref _unused, - } => { - if let Some(name) = local_path.as_ref() { - if let Some(name) = name.to_str() { - self.context.new_location(name, line as i32, col as i32) - } else { - Location::null() - } - } else { - Location::null() - } - } - }, + rustc_span::FileName::Real(ref name) => self.context.new_location( + name.path(rustc_span::RemapPathScopeComponents::DEBUGINFO).to_string_lossy(), + line as i32, + col as i32, + ), _ => Location::null(), } } From 824f41ea6f68d04bc3a01e02c1fb0150e3c5c6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:43:46 +0000 Subject: [PATCH 18/23] Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return` --- src/intrinsic/simd.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index c7ed887b30d02..39b4bb3ebefab 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -774,24 +774,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { - let elem_ty = bx.cx.type_float_from_ty(*f); - match f.bit_width() { - 16 => ("", elem_ty, Some(bx.cx.double_type)), - 32 => ("f", elem_ty, None), - 64 => ("", elem_ty, None), - _ => { - return_error!(InvalidMonomorphization::FloatingPointVector { - span, - name, - f_ty: *f, - in_ty - }); - } - } - } else { + let ty::Float(ref f) = *in_elem.kind() else { return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); }; + let elem_ty = bx.cx.type_float_from_ty(*f); + let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), + _ => { + return_error!(InvalidMonomorphization::FloatingPointVector { + span, + name, + f_ty: *f, + in_ty + }); + } + }; let vec_ty = bx.cx.type_vector(elem_ty, in_len); From f0418b3461ec949f04e803e2292c568f8816f655 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 11 Dec 2025 11:15:15 -0500 Subject: [PATCH 19/23] When we cannot load libgccjit.so, show the paths that were tried --- src/lib.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a77239e23b4e5..96d3a0024f418 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,6 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames}; -use rustc_session::filesearch::make_target_lib_path; use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tempfile::TempDir; @@ -207,18 +206,38 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { + fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf { + let rustlib_path = + rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target); + sysroot_path + .join(rustlib_path) + .join("codegen-backends") + .join("lib") + .join(sess.target.llvm_target.as_ref()) + .join("libgccjit.so") + } + // We use all_paths() instead of only path() in case the path specified by --sysroot is // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = - make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so"); + let libgccjit_target_lib_file = file_path(path, sess); if let Ok(true) = fs::exists(&libgccjit_target_lib_file) { load_libgccjit_if_needed(&libgccjit_target_lib_file); break; } } + if !gccjit::is_loaded() { + let mut paths = vec![]; + for path in sess.opts.sysroot.all_paths() { + let libgccjit_target_lib_file = file_path(path, sess); + paths.push(libgccjit_target_lib_file); + } + + panic!("Could not load libgccjit.so. Attempted paths: {:#?}", paths); + } + #[cfg(feature = "master")] { let target_cpu = target_cpu(sess); From 11bc2e0907f3bec4a1a955c76bceaa799d8489f4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 10:17:44 +0000 Subject: [PATCH 20/23] codegen: implement `repr(scalable)` Introduces `BackendRepr::ScalableVector` corresponding to scalable vector types annotated with `repr(scalable)` which lowers to a scalable vector type in LLVM. Co-authored-by: Jamie Cunliffe --- src/builder.rs | 4 ++++ src/intrinsic/mod.rs | 2 +- src/type_of.rs | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/builder.rs b/src/builder.rs index df1e64c75b963..79228c20d2927 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -943,6 +943,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } + fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> { + todo!() + } + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index a38dcf8e4c93b..d2714ba7914f3 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -504,7 +504,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } => false, + SimdVector { .. } | ScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/src/type_of.rs b/src/type_of.rs index 93202483eed81..68fca5a17ad34 100644 --- a/src/type_of.rs +++ b/src/type_of.rs @@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} + BackendRepr::ScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -179,6 +180,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + // FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc. + BackendRepr::ScalableVector { .. } => todo!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -188,6 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } From cd8cc6ff3840825681e1971f8557ddae1baa1559 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 20 Dec 2025 16:43:54 -0500 Subject: [PATCH 21/23] Update to nightly-2025-12-20 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f9645451e964d..86ae738d44839 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-11-24" +channel = "nightly-2025-12-20" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 93cf63b7899e98df3353f0b119a04f6ae18c7850 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 20 Dec 2025 16:50:34 -0500 Subject: [PATCH 22/23] Move libgccjit.so to the new location within the sysroot --- build_system/src/build.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/build_system/src/build.rs b/build_system/src/build.rs index 27476465d740d..9b7ee8380ca5c 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -111,14 +111,20 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu // Symlink libgccjit.so to sysroot. let lib_path = start_dir.join("sysroot").join("lib"); + let rustlib_target_path = lib_path + .join("rustlib") + .join(&config.host_triple) + .join("codegen-backends") + .join("lib") + .join(&config.target_triple); let libgccjit_path = PathBuf::from(config.gcc_path.as_ref().expect("libgccjit should be set by this point")) .join("libgccjit.so"); - let libgccjit_in_sysroot_path = lib_path.join("libgccjit.so"); + let libgccjit_in_sysroot_path = rustlib_target_path.join("libgccjit.so"); // First remove the file to be able to create the symlink even when the file already exists. let _ = fs::remove_file(&libgccjit_in_sysroot_path); - create_dir(&lib_path)?; - symlink(libgccjit_path, libgccjit_in_sysroot_path) + create_dir(&rustlib_target_path)?; + symlink(libgccjit_path, &libgccjit_in_sysroot_path) .map_err(|error| format!("Cannot create symlink for libgccjit.so: {}", error))?; let library_dir = start_dir.join("sysroot_src").join("library"); From 1ac26a7b1c757f55c3a5d86691c9a7b105d5d86f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 20 Dec 2025 17:31:53 -0500 Subject: [PATCH 23/23] Add new failing tests --- tests/failing-ui-tests.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 2380bd0fc137f..99a80fa7e4f44 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -88,3 +88,12 @@ tests/ui/test-attrs/test-panic-while-printing.rs tests/ui/thir-print/offset_of.rs tests/ui/iterators/rangefrom-overflow-debug.rs tests/ui/iterators/rangefrom-overflow-overflow-checks.rs +tests/ui/iterators/iter-filter-count-debug-check.rs +tests/ui/eii/codegen_single_crate.rs +tests/ui/eii/codegen_cross_crate.rs +tests/ui/eii/default/local_crate.rs +tests/ui/eii/multiple_impls.rs +tests/ui/eii/default/call_default.rs +tests/ui/eii/same-symbol.rs +tests/ui/eii/privacy1.rs +tests/ui/eii/default/call_impl.rs