From 57e44f5046058d467b9f8731f4c49885a8664d8e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Jan 2026 18:39:06 +0100 Subject: [PATCH] skip codegen for intrinsics with big fallback bodies if backend does not need them --- compiler/rustc_codegen_llvm/src/lib.rs | 6 +++++- compiler/rustc_codegen_ssa/src/traits/backend.rs | 6 ++++++ compiler/rustc_interface/src/interface.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 9 +++++---- compiler/rustc_session/src/session.rs | 7 ++++++- tests/codegen-llvm/intrinsics/carrying_mul_add.rs | 5 ++--- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 0952747449932..875b60ef6ddb8 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -42,7 +42,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; -use rustc_span::Symbol; +use rustc_span::{Symbol, sym}; use rustc_target::spec::{RelocModel, TlsModel}; use crate::llvm::ToLlvmBool; @@ -333,6 +333,10 @@ impl CodegenBackend for LlvmCodegenBackend { target_config(sess) } + fn replaced_intrinsics(&self) -> Vec { + vec![sym::unchecked_funnel_shl, sym::unchecked_funnel_shr, sym::carrying_mul_add] + } + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box { Box::new(rustc_codegen_ssa::base::codegen_crate( LlvmCodegenBackend(()), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index cb74e2e46d650..2ca24836d046f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -78,6 +78,12 @@ pub trait CodegenBackend { fn print_version(&self) {} + /// Returns a list of all intrinsics that this backend definitely + /// replaces, which means their fallback bodies do not need to be monomorphized. + fn replaced_intrinsics(&self) -> Vec { + vec![] + } + /// Value printed by `--print=backend-has-zstd`. /// /// Used by compiletest to determine whether tests involving zstd compression diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c0f8f33692e8c..c60cf9b8992ab 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -496,6 +496,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se ); codegen_backend.init(&sess); + sess.replaced_intrinsics = FxHashSet::from_iter(codegen_backend.replaced_intrinsics()); let cfg = parse_cfg(sess.dcx(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4b2f8e03afc13..622fdeb4e81c7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1001,11 +1001,12 @@ fn visit_instance_use<'tcx>( if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } - } else if !intrinsic.must_be_overridden { + } else if !intrinsic.must_be_overridden + && !tcx.sess.replaced_intrinsics.contains(&intrinsic.name) + { // Codegen the fallback body of intrinsics with fallback bodies. - // We explicitly skip this otherwise to ensure we get a linker error - // if anyone tries to call this intrinsic and the codegen backend did not - // override the implementation. + // We have to skip this otherwise as there's no body to codegen. + // We also skip intrinsics the backend handles, to reduce monomorphizations. let instance = ty::Instance::new_raw(instance.def_id(), instance.args); if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1a0ec600af47d..b3027d902b4c3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -8,7 +8,7 @@ use std::{env, io}; use rand::{RngCore, rng}; use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_data_structures::sync::{DynSend, DynSync, Lock, MappedReadGuard, ReadGuard, RwLock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; @@ -154,6 +154,10 @@ pub struct Session { /// preserved with a flag like `-C save-temps`, since these files may be /// hard linked. pub invocation_temp: Option, + + /// The names of intrinsics that the current codegen backend replaces + /// with its own implementations. + pub replaced_intrinsics: FxHashSet, } #[derive(Clone, Copy)] @@ -1091,6 +1095,7 @@ pub fn build_session( target_filesearch, host_filesearch, invocation_temp, + replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` }; validate_commandline_args_with_session_available(&sess); diff --git a/tests/codegen-llvm/intrinsics/carrying_mul_add.rs b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs index 21fb49a3786a5..844f4f6cff643 100644 --- a/tests/codegen-llvm/intrinsics/carrying_mul_add.rs +++ b/tests/codegen-llvm/intrinsics/carrying_mul_add.rs @@ -11,10 +11,9 @@ use std::intrinsics::{carrying_mul_add, fallback}; -// The fallbacks are emitted even when they're never used, but optimize out. +// The fallbacks should not be emitted. -// RAW: wide_mul_u128 -// OPT-NOT: wide_mul_u128 +// NOT: wide_mul_u128 // CHECK-LABEL: @cma_u8 #[no_mangle]