From 071a36d5b5843e13562a6e1a778781120d3330e3 Mon Sep 17 00:00:00 2001 From: N1ark Date: Sun, 15 Mar 2026 22:41:07 +0000 Subject: [PATCH 01/10] Merge `fabsfN` into `fabs::` Add `bounds::FloatPrimitive` Exhaustive float pattern match Fix GCC use span bugs --- src/intrinsic/mod.rs | 105 ++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 3f1b33c73e6..83ac627d27c 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -23,11 +23,11 @@ use rustc_codegen_ssa::traits::{ IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, }; use rustc_data_structures::fx::FxHashSet; -use rustc_middle::bug; #[cfg(feature = "master")] use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::{ArgAbi, PassMode}; @@ -70,8 +70,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f64 - sym::fabsf32 => "fabsf", - sym::fabsf64 => "fabs", sym::minimumf32 => "fminimumf", sym::minimumf64 => "fminimum", sym::minimumf128 => { @@ -194,58 +192,29 @@ fn get_simple_function<'gcc, 'tcx>( } fn get_simple_function_f128<'gcc, 'tcx>( + span: Span, cx: &CodegenCx<'gcc, 'tcx>, name: Symbol, -) -> Option> { - if !cx.supports_f128_type { - return None; - } - +) -> Function<'gcc> { let f128_type = cx.type_f128(); let func_name = match name { sym::ceilf128 => "ceilf128", - sym::fabsf128 => "fabsf128", + sym::fabs => "fabsf128", sym::floorf128 => "floorf128", sym::truncf128 => "truncf128", sym::roundf128 => "roundf128", sym::round_ties_even_f128 => "roundevenf128", sym::sqrtf128 => "sqrtf128", - _ => return None, + _ => span_bug!(span, "used get_simple_function_f128 for non-unary f128 intrinsic"), }; - Some(cx.context.new_function( + cx.context.new_function( None, FunctionType::Extern, f128_type, &[cx.context.new_parameter(None, f128_type, "a")], func_name, false, - )) -} - -fn get_simple_function_f128_2args<'gcc, 'tcx>( - cx: &CodegenCx<'gcc, 'tcx>, - name: Symbol, -) -> Option> { - if !cx.supports_f128_type { - return None; - } - - let f128_type = cx.type_f128(); - let func_name = match name { - sym::copysignf128 => "copysignf128", - _ => return None, - }; - Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - func_name, - false, - )) + ) } fn f16_builtin<'gcc, 'tcx>( @@ -257,7 +226,7 @@ fn f16_builtin<'gcc, 'tcx>( let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", sym::copysignf16 => "__builtin_copysignf", - sym::fabsf16 => "fabsf", + sym::fabs => "fabsf", sym::floorf16 => "__builtin_floorf", sym::fmaf16 => "fmaf", sym::powf16 => "__builtin_powf", @@ -297,11 +266,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let fn_args = instance.args; let simple = get_simple_intrinsic(self, name); - // FIXME(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when - // it is the symbols for the supported f128 builtins. - let simple_func = get_simple_function(self, name) - .or_else(|| get_simple_function_f128(self, name)) - .or_else(|| get_simple_function_f128_2args(self, name)); + let simple_func = get_simple_function(self, name); let value = match name { _ if simple.is_some() => { @@ -322,7 +287,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::ceilf16 | sym::copysignf16 - | sym::fabsf16 | sym::floorf16 | sym::fmaf16 | sym::powf16 @@ -331,6 +295,40 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc | sym::round_ties_even_f16 | sym::sqrtf16 | sym::truncf16 => f16_builtin(self, name, args), + sym::ceilf128 + | sym::floorf128 + | sym::truncf128 + | sym::roundf128 + | sym::round_ties_even_f128 + | sym::sqrtf128 + if self.cx.supports_f128_type => + { + let func = get_simple_function_f128(span, self, name); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } + sym::copysignf128 if self.cx.supports_f128_type => { + let f128_type = self.cx.type_f128(); + let func = self.cx.context.new_function( + None, + FunctionType::Extern, + f128_type, + &[ + self.cx.context.new_parameter(None, f128_type, "a"), + self.cx.context.new_parameter(None, f128_type, "b"), + ], + "copysignf128", + false, + ); + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } sym::fmaf128 => { let f128_type = self.cx.type_f128(); let func = self.cx.context.new_function( @@ -488,6 +486,23 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } } } + sym::fabs => 'fabs: { + let ty = args[0].layout.ty; + let ty::Float(float_ty) = *ty.kind() else { + span_bug!(span, "expected float type for fabs intrinsic: {:?}", ty); + }; + let func = match float_ty { + ty::FloatTy::F16 => break 'fabs f16_builtin(self, name, args), + ty::FloatTy::F32 => self.context.get_builtin_function("fabsf"), + ty::FloatTy::F64 => self.context.get_builtin_function("fabs"), + ty::FloatTy::F128 => get_simple_function_f128(span, self, name), + }; + self.cx.context.new_call( + self.location, + func, + &args.iter().map(|arg| arg.immediate()).collect::>(), + ) + } sym::raw_eq => { use rustc_abi::BackendRepr::*; From 383705eedc9d7346cb639559d595afbf26ed2181 Mon Sep 17 00:00:00 2001 From: N1ark Date: Sat, 14 Mar 2026 12:54:21 +0000 Subject: [PATCH 02/10] Remove `InvalidMonomorphization::FloatingPointType` --- src/intrinsic/simd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 1263b2285a8..1900572eee7 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -811,7 +811,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( }}; } let ty::Float(ref f) = *in_elem.kind() else { - return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty }); + return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty }); }; let elem_ty = bx.cx.type_float_from_ty(*f); let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() { From 646b64f9c0083b4f9b4cead888b10351397b7600 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2026 15:04:47 +0100 Subject: [PATCH 03/10] simd_fmin/fmax: make semantics and name consistent with scalar intrinsics --- src/builder.rs | 11 +++++++---- src/intrinsic/simd.rs | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 6add7f05c2a..3eb0fd95284 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2278,6 +2278,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }) } + /// Emits a SIMD min/max operation for floats. The semantics for each lane are: if one + /// side is NaN (QNaN or SNaN), the other side is returned. fn vector_extremum( &mut self, a: RValue<'gcc>, @@ -2286,8 +2288,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ) -> RValue<'gcc> { let vector_type = a.get_type(); - // mask out the NaNs in b and replace them with the corresponding lane in a, so when a and - // b get compared & spliced together, we get the numeric values instead of NaNs. + // Mask out the NaNs (both QNaN and SNaN) in b and replace them with the corresponding lane + // in a, so when a and b get compared & spliced together, we get the numeric values instead + // of NaNs. let b_nan_mask = self.context.new_comparison(self.location, ComparisonOp::NotEquals, b, b); let mask_type = b_nan_mask.get_type(); let b_nan_mask_inverted = @@ -2309,7 +2312,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.context.new_bitcast(self.location, res, vector_type) } - pub fn vector_fmin(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_minimum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.vector_extremum(a, b, ExtremumOperation::Min) } @@ -2341,7 +2344,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - pub fn vector_fmax(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn vector_maximum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { self.vector_extremum(a, b, ExtremumOperation::Max) } diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 1263b2285a8..06254fcb180 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1222,8 +1222,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( simd_and: Uint, Int => and; simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors. simd_xor: Uint, Int => xor; - simd_fmin: Float => vector_fmin; - simd_fmax: Float => vector_fmax; + simd_minimum_number_nsz: Float => vector_minimum_number_nsz; + simd_maximum_number_nsz: Float => vector_maximum_number_nsz; } macro_rules! arith_unary { From 36ac53572f4a7ec4b080e969a3a216c7921462f5 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 Apr 2026 21:29:42 -0500 Subject: [PATCH 04/10] Revert "Fix: On wasm targets, call `panic_in_cleanup` if panic occurs in cleanup" This reverts commit acbfd79acf662be04745dc0675558e75e0d30d87. --- src/builder.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 3eb0fd95284..1d6d7760441 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1656,10 +1656,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } - fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { - unimplemented!(); - } - // Atomic Operations fn atomic_cmpxchg( &mut self, From c5fc5794d742747d21806693bf0c7ff5b19be87d Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 19 Feb 2026 11:03:14 +0000 Subject: [PATCH 05/10] ty_utils: lower tuples to `ScalableVector` repr Instead of just using regular struct lowering for these types, which results in an incorrect ABI (e.g. returning indirectly), use `BackendRepr::ScalableVector` which will lower to the correct type and be passed in registers. This also enables some simplifications for generating alloca of scalable vectors and greater re-use of `scalable_vector_parts`. A LLVM codegen test demonstrating the changed IR this generates is included in the next commit alongside some intrinsics that make these tuples usable. --- src/builder.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 1d6d7760441..3cffd862b9b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -24,7 +24,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{ - FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt}; use rustc_span::Span; @@ -943,8 +944,8 @@ 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 alloca_with_ty(&mut self, ty: TyAndLayout<'tcx>) -> RValue<'gcc> { + self.alloca(ty.layout.size, ty.layout.align.abi) } fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { From 165fa89305158543cdf2cf70617f22772101e1c9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 26 Feb 2026 15:35:20 +0000 Subject: [PATCH 06/10] cg_llvm/debuginfo: scalable vectors Generate debuginfo for scalable vectors, following the structure that Clang generates for scalable vectors. --- src/common.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common.rs b/src/common.rs index 9e548ac0a8b..dd0064d34bc 100644 --- a/src/common.rs +++ b/src/common.rs @@ -145,6 +145,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { self.const_int(self.type_i32(), i as i64) } + fn const_i64(&self, i: i64) -> RValue<'gcc> { + self.const_int(self.type_i64(), i) + } + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { self.gcc_int(typ, int) } From b26e2fdab559a367436848cfa0b7c56d5d61bffe Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 8 Apr 2026 16:01:39 -0400 Subject: [PATCH 07/10] Update to nightly-2026-04-05 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 3d64e544353..796a468daab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-03-26" +channel = "nightly-2026-04-05" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] From 2a8edb2bb2aa56b007bccb9483413f8a1934ec7d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 8 Apr 2026 16:01:50 -0400 Subject: [PATCH 08/10] Format the code --- src/intrinsic/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 9a586d6a3af..a44cd1f7347 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -128,7 +128,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( "powf128", false, )); - }, + } sym::truncf32 => "truncf", sym::truncf64 => "trunc", // We match the LLVM backend and lower this to `rint`. From 7db7c9b93c220d3f7ff9d218c46b2a503b844c11 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 17 Apr 2026 16:21:46 -0400 Subject: [PATCH 09/10] Ignore failing UI tests --- tests/failing-ui-tests.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 5739b2cbd5d..1257193bf96 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -103,3 +103,5 @@ tests/ui/lto/all-crates.rs tests/ui/consts/const-eval/c-variadic.rs tests/ui/eii/default/call_default_panics.rs tests/ui/explicit-tail-calls/indirect.rs +tests/ui/traits/inheritance/self-in-supertype.rs +tests/ui/fmt/fmt_debug/shallow.rs From 0c99072215e8a939b131b7c64fff8b0d6edaa905 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 17 Apr 2026 17:09:01 -0400 Subject: [PATCH 10/10] Fix maximum/minimum float intrinsics --- src/intrinsic/mod.rs | 80 +++++++++++++------------------------------- 1 file changed, 24 insertions(+), 56 deletions(-) diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index a44cd1f7347..ee17f4e2f55 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -4,9 +4,7 @@ mod simd; #[cfg(feature = "master")] use std::iter; -#[cfg(feature = "master")] -use gccjit::Type; -use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, UnaryOp}; +use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp}; #[cfg(feature = "master")] use rustc_abi::ExternAbi; use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange}; @@ -40,6 +38,22 @@ use crate::context::CodegenCx; use crate::intrinsic::simd::generic_simd_intrinsic; use crate::type_of::LayoutGccExt; +fn float_intrinsic<'gcc, 'tcx>( + cx: &CodegenCx<'gcc, 'tcx>, + typ: Type<'gcc>, + name: &str, +) -> Option> { + // GCC doesn't have the intrinsic we want so we use the compiler-builtins one + Some(cx.context.new_function( + None, + FunctionType::Extern, + typ, + &[cx.context.new_parameter(None, typ, "a"), cx.context.new_parameter(None, typ, "b")], + name, + false, + )) +} + fn get_simple_intrinsic<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, name: Symbol, @@ -70,65 +84,19 @@ fn get_simple_intrinsic<'gcc, 'tcx>( // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f64 - sym::minimumf32 => "fminimumf", - sym::minimumf64 => "fminimum", - sym::minimumf128 => { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one - // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fminimumf128.html - let f128_type = cx.type_f128(); - return Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - "fminimumf128", - false, - )); - } - sym::maximumf32 => "fmaximumf", - sym::maximumf64 => "fmaximum", - sym::maximumf128 => { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one - // https://docs.rs/compiler_builtins/latest/compiler_builtins/math/full_availability/fn.fmaximumf128.html - let f128_type = cx.type_f128(); - return Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - "fmaximumf128", - false, - )); - } + sym::minimumf32 => return float_intrinsic(cx, cx.type_f32(), "fminimumf"), + sym::minimumf64 => return float_intrinsic(cx, cx.type_f64(), "fminimum"), + sym::minimumf128 => return float_intrinsic(cx, cx.type_f128(), "fminimumf128"), + sym::maximumf32 => return float_intrinsic(cx, cx.type_f32(), "fmaximumf"), + sym::maximumf64 => return float_intrinsic(cx, cx.type_f64(), "fmaximum"), + sym::maximumf128 => return float_intrinsic(cx, cx.type_f128(), "fmaximumf128"), sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", sym::ceilf64 => "ceil", - sym::powf128 => { - // GCC doesn't have the intrinsic we want so we use the compiler-builtins one. - // FIXME(antoyo): there's some duplication here with functions like minimumf128, - // copysignf128 and maximumf128. - let f128_type = cx.type_f128(); - return Some(cx.context.new_function( - None, - FunctionType::Extern, - f128_type, - &[ - cx.context.new_parameter(None, f128_type, "a"), - cx.context.new_parameter(None, f128_type, "b"), - ], - "powf128", - false, - )); - } + sym::powf128 => return float_intrinsic(cx, cx.type_f128(), "powf128"), sym::truncf32 => "truncf", sym::truncf64 => "trunc", // We match the LLVM backend and lower this to `rint`.