From 48fa3e32961a4cddc02535807a89024ba129d186 Mon Sep 17 00:00:00 2001 From: Jorge Ortega Date: Fri, 25 Apr 2025 21:42:30 -0700 Subject: [PATCH] fix(rustc_codegen_nvvm): Check function signatures before overriding libm functions. libm 0.2.13 refactored some of its implementations to use generic functions. The monomorphized function names clashed with the function names the codegen would override, causing it the codegen to override the function to a libdevice call that did not match the function signature. It then tries to patch this with a bitcast betwen floating point types, which are invalid casts. This change adds an additional check before overriding. The libm function signature must match the libdevice intrinsic signature of the same name. Note that this prevents overrides even if bitcasts between the two argument types would be valid, which is likely another bug anyways. --- crates/rustc_codegen_nvvm/src/override_fns.rs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/crates/rustc_codegen_nvvm/src/override_fns.rs b/crates/rustc_codegen_nvvm/src/override_fns.rs index dc5515df..9f44fe4c 100644 --- a/crates/rustc_codegen_nvvm/src/override_fns.rs +++ b/crates/rustc_codegen_nvvm/src/override_fns.rs @@ -2,11 +2,16 @@ //! codegen-builtin methods. Currently the only use for this is overriding libm functions //! with libdevice intrinsics (which are much faster and smaller). -use crate::{builder::Builder, context::CodegenCx, llvm}; +use crate::abi::FnAbiLlvmExt; +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::llvm; use rustc_codegen_ssa::mono_item::MonoItemExt; -use rustc_codegen_ssa::traits::BuilderMethods; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::{mir::mono::MonoItem, ty::Instance}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::{self, Instance}; /// Either override or define a function. pub(crate) fn define_or_override_fn<'tcx>(func: Instance<'tcx>, cx: &CodegenCx<'_, 'tcx>) { @@ -27,12 +32,24 @@ fn should_override<'tcx>(func: Instance<'tcx>, cx: &CodegenCx<'_, 'tcx>) -> bool if !is_libm { return false; } + let sym = cx.tcx.item_name(func.def_id()); let name = sym.as_str(); - let intrinsics = cx.intrinsics_map.borrow(); - let is_known_intrinsic = intrinsics.contains_key(format!("__nv_{}", name).as_str()); - !is_unsupported_libdevice_fn(name) && is_known_intrinsic + if is_unsupported_libdevice_fn(name) { + return false; + } + + let libdevice_name = format!("__nv_{}", name); + let ld_fn = if let Some((args, ret)) = cx.intrinsics_map.borrow().get(libdevice_name.as_str()) { + cx.type_func(args, ret) + } else { + return false; + }; + + // Check the function signatures match. + let lm_fn = cx.fn_abi_of_instance(func, ty::List::empty()).llvm_type(cx); + lm_fn == ld_fn } fn is_unsupported_libdevice_fn(name: &str) -> bool {