From 66f69fc2ffe2691a3b97e99d86908f5ee5d86b67 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 17 Sep 2026 01:04:17 -0400 Subject: [PATCH] No longer auto-inline `f16` and `f128` on well-supported platforms In 5d818914af27 ("Always inline functions signatures containing `f16` or `f128`"), these types were changed to automatically inline so codegen wouldn't crash on poorly-supported platforms. We have since gained a cfg to reflect the type's codegen reliability. Update so we only check and auto-inline based on type if this config is set, which makes `f16` and `f128` act more like any other type on most platforms. We still can't remove this entirely since a lot of API in `std` wouldn't get inlined and would crash the few remaining poorly-supported backend+target combinations. --- .../src/cross_crate_inline.rs | 22 +++-- tests/codegen-llvm/float/f16-f128-inline.rs | 91 +++++++++++++++---- 2 files changed, 87 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 8a4e7740650fc..ca47b27d142a2 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{InliningThreshold, OptLevel}; -use rustc_span::bug; +use rustc_span::{bug, sym}; use crate::{inline, pass_manager as pm}; @@ -64,13 +64,19 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return true; } - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); - for ty in sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder())) - { - // FIXME(f16_f128): in order to avoid crashes building `core`, always inline to skip - // codegen if the function is not used. - if ty == &tcx.types.f16 || ty == &tcx.types.f128 { - return true; + let reliable_f16 = tcx.sess.config.contains(&(sym::target_has_reliable_f16, None)); + let reliable_f128 = tcx.sess.config.contains(&(sym::target_has_reliable_f128, None)); + if !reliable_f16 || !reliable_f128 { + let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + for ty in + sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder())) + { + // FIXME(f16,f128): in order to avoid crashes building `core`, inline on targets that + // have issues to skip codegen if the function is not used. + if (!reliable_f16 && ty == &tcx.types.f16) || (!reliable_f128 && ty == &tcx.types.f128) + { + return true; + } } } diff --git a/tests/codegen-llvm/float/f16-f128-inline.rs b/tests/codegen-llvm/float/f16-f128-inline.rs index aa2c38c209e86..592204cf000a1 100644 --- a/tests/codegen-llvm/float/f16-f128-inline.rs +++ b/tests/codegen-llvm/float/f16-f128-inline.rs @@ -1,29 +1,84 @@ -//@ revisions: default nopt -//@[nopt] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes +//@ revisions: DEFAULT NOPT +//@[NOPT] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes -// Ensure that functions using `f16` and `f128` are always inlined to avoid crashes -// when the backend does not support these types. +// Ensure that functions using `f16` and `f128` are always inlined when the backend does not +// support these types, to avoid crashes. #![crate_type = "lib"] #![feature(f128)] #![feature(f16)] +#![feature(cfg_target_has_reliable_f16_f128)] -pub fn f16_arg(_a: f16) { - // CHECK-NOT: f16_arg - todo!() -} +// This test does some tricky things. On `target_has_reliable_*` platforms: +// +// * `*_on_reliable` functions should always show up in codegen since they are not auto-inlined +// (the default), +// * `*_on_not_reliable` functions aren't defined at all, so `CHECK-NOT` passes. +// +// On non-`target_has_reliable_*` platforms: +// +// * `*_on_reliable` functions are dummies so they always show up in codegen. +// * `*_on_not_reliable` functions should be auto-inlined and thus not show up in codegen. +// +// `*_on_reliable` is only checked with NOPT since otherwise they may hit auto-inlining thresholds +// unrelated to the type signature. -pub fn f16_ret() -> f16 { - // CHECK-NOT: f16_ret - todo!() -} +// NOPT: f16_arg_on_reliable +// NOPT: f16_ret_on_reliable +// CHECK-NOT: f16_arg_on_not_reliable +// CHECK-NOT: f16_ret_on_not_reliable +cfg_select! { + target_has_reliable_f16 => { + pub fn f16_arg_on_reliable(_a: f16) { + todo!() + } + + pub fn f16_ret_on_reliable() -> f16 { + todo!() + } + } + _ => { + pub fn f16_arg_on_not_reliable(_a: f16) { + todo!() + } + + pub fn f16_ret_on_not_reliable() -> f16 { + todo!() + } -pub fn f128_arg(_a: f128) { - // CHECK-NOT: f128_arg - todo!() + #[unsafe(no_mangle)] + pub fn f16_arg_on_reliable() {} + #[unsafe(no_mangle)] + pub fn f16_ret_on_reliable() {} + } } -pub fn f128_ret() -> f128 { - // CHECK-NOT: f128_ret - todo!() +// NOPT: f128_arg_on_reliable +// NOPT: f128_ret_on_reliable +// CHECK-NOT: f128_arg_on_not_reliable +// CHECK-NOT: f128_ret_on_not_reliable +cfg_select! { + target_has_reliable_f128 => { + pub fn f128_arg_on_reliable(_a: f128) { + todo!() + } + + pub fn f128_ret_on_reliable() -> f128 { + todo!() + } + } + _ => { + pub fn f128_arg_on_not_reliable(_a: f128) { + todo!() + } + + pub fn f128_ret_on_not_reliable() -> f128 { + todo!() + } + + #[unsafe(no_mangle)] + pub fn f128_arg_on_reliable() {} + #[unsafe(no_mangle)] + pub fn f128_ret_on_reliable() {} + } }