From 2ac135173d1a571be069d040e4f833c85cdab502 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 11:59:33 +1000 Subject: [PATCH 1/2] Split `build_session` Session creation is currently awkward: we build a mostly-initialized session, then use it to initialize a codegen backend, and then use the codegen backend to finish initializing the session. And it's not just awkward: within the Cranelift backend's `init` method `sess.lto()` is called, which consults `sess.thin_lto_supported`, *before* that field has been properly set! This commit cleans up this mess. It introduces `EarlySession`, which contains just four `Session` fields, the ones that are needed for codegen backend initialization. This is passed to `init`. `init` then returns a `CodegenBackendInit` which contains the backend-specific information needed to build a `Session`. (It replaces the `replaced_intrinsics`, `fallback_intrinsics`, and `thin_lto_supported` methods.) The `Session` can then be built in a single step. No more partial initialization problems. A few functions that previously took a `Session` now take something else, e.g. a `Target`, because they are used from some places where an `EarlySession` is available and other places where a `Session` is available. And a new `early_lto` method is used for Cranelift's LTO check. --- compiler/rustc_codegen_cranelift/src/lib.rs | 27 +++--- compiler/rustc_codegen_gcc/src/base.rs | 2 +- compiler/rustc_codegen_gcc/src/context.rs | 4 +- compiler/rustc_codegen_gcc/src/gcc_util.rs | 10 +-- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 22 +++-- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/context.rs | 4 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +- compiler/rustc_codegen_llvm/src/lib.rs | 90 +++++++++---------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 10 +-- compiler/rustc_codegen_ssa/src/base.rs | 15 ++-- compiler/rustc_codegen_ssa/src/mir/block.rs | 14 +-- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- .../rustc_codegen_ssa/src/traits/backend.rs | 23 +---- compiler/rustc_interface/src/interface.rs | 38 ++++---- compiler/rustc_interface/src/tests.rs | 11 ++- compiler/rustc_session/src/session.rs | 85 +++++++++++++++--- src/tools/miri/src/bin/miri.rs | 4 +- 19 files changed, 205 insertions(+), 164 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8b0ca770ec067..5fff7efeabeee 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -43,7 +43,7 @@ use rustc_data_structures::unord::UnordSet; use rustc_log::tracing::info; use rustc_middle::dep_graph::WorkProductMap; use rustc_session::config::{NATIVE_CPU, OutputFilenames}; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Arch, CfgAbi, Env, Os}; @@ -126,13 +126,14 @@ impl CodegenBackend for CraneliftCodegenBackend { "cranelift" } - fn init(&self, sess: &Session) { - use rustc_session::config::{InstrumentCoverage, Lto}; - match sess.lto() { - Lto::No | Lto::ThinLocal => {} - Lto::Thin | Lto::Fat => { - sess.dcx().fatal("LTO is not supported by rustc_codegen_cranelift"); + fn init(&self, sess: &EarlySession) -> CodegenBackendInit { + use rustc_session::config::{InstrumentCoverage, LtoCli}; + + match (sess.target.requires_lto, sess.early_lto()) { + (true, _) | (false, LtoCli::Yes | LtoCli::Fat | LtoCli::NoParam | LtoCli::Thin) => { + sess.dcx().fatal("LTO is not supported by rustc_codegen_cranelift") } + (false, LtoCli::Unspecified | LtoCli::No) => {} } if sess.opts.cg.instrument_coverage() != InstrumentCoverage::No { @@ -148,10 +149,12 @@ impl CodegenBackend for CraneliftCodegenBackend { if config.jit_mode && !sess.opts.output_types.should_codegen() { sess.dcx().fatal("JIT mode doesn't work with `cargo check`"); } - } - fn thin_lto_supported(&self) -> bool { - false + CodegenBackendInit { + replaced_intrinsics: vec![], + fallback_intrinsics: vec![sym::type_id_eq], + thin_lto_supported: false, + } } fn target_config(&self, sess: &Session) -> TargetConfig { @@ -240,10 +243,6 @@ impl CodegenBackend for CraneliftCodegenBackend { .unwrap() .join(sess, incr_comp_session, crate_info) } - - fn fallback_intrinsics(&self) -> Vec { - vec![sym::type_id_eq] - } } /// Determine if the Cranelift ir verifier should run. diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 7a25fc46fd3fc..14c0fc0958cde 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -162,7 +162,7 @@ pub fn compile_codegen_unit( add_pic_option(&context, tcx.sess.relocation_model()); - let target_cpu = gcc_util::target_cpu(tcx.sess); + let target_cpu = gcc_util::target_cpu(&tcx.sess.opts, &tcx.sess.target); if target_cpu != "generic" { context.add_command_line_option(format!("-march={}", target_cpu)); } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 8045e8ae9d28f..683ebfa5a1e7b 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -451,7 +451,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } let tcx = self.tcx; let func = match tcx.lang_items().eh_personality() { - Some(def_id) if !wants_msvc_seh(self.sess()) => { + Some(def_id) if !wants_msvc_seh(&self.sess().target) => { let instance = ty::Instance::expect_resolve( tcx, self.typing_env(), @@ -466,7 +466,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.declare_fn(symbol_name, fn_abi) } _ => { - let name = if wants_msvc_seh(self.sess()) { + let name = if wants_msvc_seh(&self.sess().target) { "__CxxFrameHandler3" } else { "rust_eh_personality" diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index a95b4da28eb63..8580e20619bfb 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -3,8 +3,8 @@ use gccjit::Context; use rustc_codegen_ssa::target_features; use rustc_data_structures::smallvec::{SmallVec, smallvec}; use rustc_session::Session; -use rustc_session::config::NATIVE_CPU; -use rustc_target::spec::Arch; +use rustc_session::config::{NATIVE_CPU, Options}; +use rustc_target::spec::{Arch, Target}; fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); @@ -130,9 +130,9 @@ fn handle_native(name: &str) -> &str { unimplemented!(); } -pub fn target_cpu(sess: &Session) -> &str { - match sess.opts.cg.target_cpu { +pub fn target_cpu<'a>(sopts: &'a Options, target: &'a Target) -> &'a str { + match sopts.cg.target_cpu { Some(ref name) => handle_native(name), - None => handle_native(sess.target.cpu.as_ref()), + None => handle_native(target.cpu.as_ref()), } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 09ad3254e5714..468ef20d78a9e 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -1353,7 +1353,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( // we can never unwind. OperandValue::Immediate(bx.const_bool(false)).store(bx, dest); } else { - if wants_msvc_seh(bx.sess()) { + if wants_msvc_seh(&bx.sess().target) { unimplemented!(); } #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index cbc7db8e9e23f..87e6c7224471f 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -95,7 +95,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductMap}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::config::{OptLevel, OutputFilenames}; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Arch, RelocModel}; use tempfile::TempDir; @@ -195,8 +195,8 @@ impl CodegenBackend for GccCodegenBackend { "gcc" } - fn init(&self, sess: &Session) { - fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf { + fn init(&self, sess: &EarlySession) -> CodegenBackendInit { + fn file_path(sysroot_path: &Path, sess: &EarlySession) -> PathBuf { let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target); sysroot_path @@ -232,7 +232,7 @@ impl CodegenBackend for GccCodegenBackend { { gccjit::set_lang_name(c"GNU Rust"); - let target_cpu = target_cpu(sess); + let target_cpu = target_cpu(&sess.opts, &sess.target); // Get the second TargetInfo with the correct CPU features by setting the arch. let context = Context::default(); @@ -274,10 +274,12 @@ impl CodegenBackend for GccCodegenBackend { .supports_128bit_integers .store(check_context.get_last_error() == Ok(None), Ordering::SeqCst); } - } - fn thin_lto_supported(&self) -> bool { - false + CodegenBackendInit { + replaced_intrinsics: vec![], + fallback_intrinsics: vec![sym::type_id_eq], + thin_lto_supported: false, + } } fn provide(&self, providers: &mut Providers) { @@ -286,7 +288,7 @@ impl CodegenBackend for GccCodegenBackend { } fn target_cpu(&self, sess: &Session) -> String { - target_cpu(sess).to_owned() + target_cpu(&sess.opts, &sess.target).to_owned() } fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { @@ -310,10 +312,6 @@ impl CodegenBackend for GccCodegenBackend { fn target_config(&self, sess: &Session) -> TargetConfig { target_config(sess, &self.target_info) } - - fn fallback_intrinsics(&self) -> Vec { - vec![sym::type_id_eq] - } } fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 66b51d9184a79..2bf5695e41da3 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -255,7 +255,7 @@ pub(crate) fn target_machine_factory( } }; - let use_wasm_eh = wants_wasm_eh(sess); + let use_wasm_eh = wants_wasm_eh(&sess.target); let large_data_threshold = sess.opts.unstable_opts.large_data_threshold.unwrap_or(0); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 668072ff082ec..91e1a5cb18f7d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -966,9 +966,9 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { return llpersonality; } - let name = if wants_msvc_seh(self.sess()) { + let name = if wants_msvc_seh(&self.sess().target) { Some("__CxxFrameHandler3") - } else if wants_wasm_eh(self.sess()) { + } else if wants_wasm_eh(&self.sess().target) { // LLVM specifically tests for the name of the personality function // There is no need for this function to exist anywhere, it will // not be called. However, its name has to be "__gxx_wasm_personality_v0" diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index ba11ef29fb536..4d01e80b202c2 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1345,9 +1345,9 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( // Return 0 unconditionally from the intrinsic call; // we can never unwind. bx.const_bool(false) - } else if wants_msvc_seh(bx.sess()) { + } else if wants_msvc_seh(&bx.sess().target) { codegen_msvc_try(bx, try_func, data, catch_func) - } else if wants_wasm_eh(bx.sess()) { + } else if wants_wasm_eh(&bx.sess().target) { codegen_wasm_try(bx, try_func, data, catch_func) } else { codegen_gnu_try(bx, try_func, data, catch_func) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 552a91ffee071..ca6c68bdc21e4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -39,7 +39,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductMap}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{RelocModel, TlsModel}; @@ -219,7 +219,7 @@ impl CodegenBackend for LlvmCodegenBackend { "llvm" } - fn init(&self, sess: &Session) { + fn init(&self, sess: &EarlySession) -> CodegenBackendInit { llvm_util::init(sess); // Make sure llvm is inited // autodiff is based on Enzyme, a library which we might not have available, when it was @@ -243,6 +243,49 @@ impl CodegenBackend for LlvmCodegenBackend { enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } } + + // Intrinsics whose fallback body will not be used by the LLVM backend. + let replaced_intrinsics = { + #[rustfmt::skip] + let mut will_not_use_fallback = vec![ + // These are mapped to LLVM intrinsics instead. + sym::unchecked_funnel_shl, + sym::unchecked_funnel_shr, + sym::carrying_mul_add, + + // Fallback via libm, but the LLVM intrinsic is used instead. + sym::sinf16, sym::sinf32, sym::sinf64, + sym::cosf16, sym::cosf32, sym::cosf64, + sym::powf16, sym::powf32, sym::powf64, + sym::expf16, sym::expf32, sym::expf64, + sym::exp2f16, sym::exp2f32, sym::exp2f64, + sym::logf16, sym::logf32, sym::logf64, + sym::log10f16, sym::log10f32, sym::log10f64, + sym::log2f16, sym::log2f32, sym::log2f64, + + // Fallback via f32 or f64, but the LLVM intrinsic is used instead. + sym::floorf16, sym::ceilf16, sym::truncf16, + sym::round_ties_even_f16, sym::roundf16, + sym::sqrtf16, sym::powif16, + sym::fmaf16, + + sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128, + ]; + + if llvm_util::get_version() >= (22, 0, 0) { + will_not_use_fallback.push(sym::carryless_mul); + } + + will_not_use_fallback + }; + + // `type_id_eq` is a safe choice since *all* backends use the fallback body for that. When + // adding more intrinsics, keep in mind that the distributed standard library is compiled + // with the LLVM backend but might later be included in a project built with cranelift or + // GCC. + let fallback_intrinsics = vec![sym::type_id_eq]; + + CodegenBackendInit { replaced_intrinsics, fallback_intrinsics, thin_lto_supported: true } } fn provide(&self, providers: &mut Providers) { @@ -325,49 +368,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_config(sess) } - /// Intrinsics whose fallback body will not be used by the LLVM backend. - fn replaced_intrinsics(&self) -> Vec { - #[rustfmt::skip] - let mut will_not_use_fallback = vec![ - // These are mapped to LLVM intrinsics instead. - sym::unchecked_funnel_shl, - sym::unchecked_funnel_shr, - sym::carrying_mul_add, - - // Fallback via libm, but the LLVM intrinsic is used instead. - sym::sinf16, sym::sinf32, sym::sinf64, - sym::cosf16, sym::cosf32, sym::cosf64, - sym::powf16, sym::powf32, sym::powf64, - sym::expf16, sym::expf32, sym::expf64, - sym::exp2f16, sym::exp2f32, sym::exp2f64, - sym::logf16, sym::logf32, sym::logf64, - sym::log10f16, sym::log10f32, sym::log10f64, - sym::log2f16, sym::log2f32, sym::log2f64, - - // Fallback via f32 or f64, but the LLVM intrinsic is used instead. - sym::floorf16, sym::ceilf16, sym::truncf16, - sym::round_ties_even_f16, sym::roundf16, - sym::sqrtf16, sym::powif16, - sym::fmaf16, - - sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128, - ]; - - if llvm_util::get_version() >= (22, 0, 0) { - will_not_use_fallback.push(sym::carryless_mul); - } - - will_not_use_fallback - } - - fn fallback_intrinsics(&self) -> Vec { - // `type_id_eq` is a safe choice since *all* backends use the fallback body for that. - // When adding more intrinsics, keep in mind that the distributed standard library - // is compiled with the LLVM backend but might later be included in a project built - // with cranelift or GCC. - vec![sym::type_id_eq] - } - fn target_cpu(&self, sess: &Session) -> String { crate::llvm_util::target_cpu(sess).to_string() } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 298b58dd0007f..4cd16a5b17927 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -13,8 +13,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; -use rustc_session::Session; use rustc_session::config::{NATIVE_CPU, PrintKind, PrintRequest}; +use rustc_session::{EarlySession, Session}; use rustc_target::spec::{ Arch, CfgAbi, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport, }; @@ -25,7 +25,7 @@ use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); -pub(crate) fn init(sess: &Session) { +pub(crate) fn init(sess: &EarlySession) { unsafe { // Before we touch LLVM, make sure that multithreading is enabled. if !llvm::LLVMIsMultithreaded().is_true() { @@ -43,7 +43,7 @@ fn require_inited() { } } -unsafe fn configure_llvm(sess: &Session) { +unsafe fn configure_llvm(sess: &EarlySession) { let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len(); let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); @@ -105,7 +105,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if wants_wasm_eh(sess) { + if wants_wasm_eh(&sess.target) { add("-wasm-enable-eh", false); } @@ -633,7 +633,7 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { /// The target features for compiler flags other than `-Ctarget-features`. fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { - if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind { + if wants_wasm_eh(&sess.target) && sess.panic_strategy() == PanicStrategy::Unwind { features.push("+exception-handling".into()); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 0468e3de18d8b..8d6f2c15e306c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -29,11 +29,10 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, PatternKind, Ty, TyCtxt, UintTy, Unnormalized}; use rustc_middle::{bug, span_bug}; -use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType}; use rustc_span::{DUMMY_SP, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{Arch, Os}; +use rustc_target::spec::{Arch, Os, Target as SpecTarget}; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; @@ -372,8 +371,8 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Returns `true` if this session's target will use native wasm // exceptions. This means that the VM does the unwinding for // us -pub fn wants_wasm_eh(sess: &Session) -> bool { - sess.target.is_like_wasm +pub fn wants_wasm_eh(target: &SpecTarget) -> bool { + target.is_like_wasm } /// Returns `true` if this session's target will use SEH-based unwinding. @@ -381,15 +380,15 @@ pub fn wants_wasm_eh(sess: &Session) -> bool { /// This is only true for MSVC targets, and even then the 64-bit MSVC target /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as /// 64-bit MinGW) instead of "full SEH". -pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.is_like_msvc +pub fn wants_msvc_seh(target: &SpecTarget) -> bool { + target.is_like_msvc } /// Returns `true` if this session's target requires the new exception /// handling LLVM IR instructions (catchpad / cleanuppad / ... instead /// of landingpad) -pub(crate) fn wants_new_eh_instructions(sess: &Session) -> bool { - wants_wasm_eh(sess) || wants_msvc_seh(sess) +pub(crate) fn wants_new_eh_instructions(target: &SpecTarget) -> bool { + wants_wasm_eh(target) || wants_msvc_seh(target) } pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 7f907bc630b2f..7179a1225b4fc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } if is_cleanupret { // Cross-funclet jump - need a trampoline - assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess)); + assert!(base::wants_new_eh_instructions(&fx.cx.tcx().sess.target)); debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target); let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target); let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name); @@ -228,12 +228,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) { + if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(&fx.cx.tcx().sess.target) { // For wasm, we need to generate a nested `cleanuppad within %outer_pad` // to catch exceptions during cleanup and call `panic_in_cleanup`. Some(fx.terminate_block(reason, Some(self.bb))) } else if fx.mir[self.bb].is_cleanup - && base::wants_new_eh_instructions(fx.cx.tcx().sess) + && base::wants_new_eh_instructions(&fx.cx.tcx().sess.target) { // MSVC SEH will abort automatically if an exception tries to // propagate out from cleanup. @@ -2176,7 +2176,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // FIXME(eddyb) rename this to `eh_pad_for_uncached`. fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock { let llbb = self.llbb(bb); - if base::wants_new_eh_instructions(self.cx.sess()) { + if base::wants_new_eh_instructions(&self.cx.sess().target) { let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{bb:?}")); let mut cleanup_bx = Bx::build(self.cx, cleanup_bb); let funclet = cleanup_bx.cleanup_pad(None, &[]); @@ -2220,7 +2220,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // what outer catch_pad it is contained in. debug_assert!( outer_catchpad_bb.is_some() - == (base::wants_wasm_eh(self.cx.tcx().sess) + == (base::wants_wasm_eh(&self.cx.tcx().sess.target) && reason == UnwindTerminateReason::InCleanup) ); @@ -2250,7 +2250,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let funclet; let llbb; let mut bx; - if base::wants_new_eh_instructions(self.cx.sess()) { + if base::wants_new_eh_instructions(&self.cx.sess().target) { // This is a basic block that we're aborting the program for, // notably in an `extern` function. These basic blocks are inserted // so that we assert that `extern` functions do indeed not panic, @@ -2316,7 +2316,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The `null` in first argument here is actually a RTTI type // descriptor for the C++ personality function, but `catch (...)` // has no type so it's null. - let args = if base::wants_msvc_seh(self.cx.sess()) { + let args = if base::wants_msvc_seh(&self.cx.sess().target) { // This bitmask is a single `HT_IsStdDotDot` flag, which // represents that this is a C++-style `catch (...)` block that // only captures programmatic exceptions, not all SEH diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index f8f4f09f75825..02e156b9960d6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -245,7 +245,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( start_bx.set_personality_fn(cx.eh_personality()); } - let cleanup_kinds = base::wants_new_eh_instructions(tcx.sess) + let cleanup_kinds = base::wants_new_eh_instructions(&tcx.sess.target) .then(|| analyze::cleanup_kinds(&mir, &nop_landing_pads)); let cached_llbbs: IndexVec> = diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 36f4d858d0be5..eed4a48d5e2e8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -9,7 +9,7 @@ use rustc_middle::dep_graph::WorkProductMap; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OutputFilenames, PrintRequest}; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; use rustc_span::Symbol; use super::CodegenObject; @@ -36,7 +36,9 @@ pub trait BackendTypes { pub trait CodegenBackend { fn name(&self) -> &'static str; - fn init(&self, _sess: &Session) {} + fn init(&self, _sess: &EarlySession) -> CodegenBackendInit { + Default::default() + } fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} @@ -70,23 +72,6 @@ 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![] - } - - /// Returns a list of all intrinsics that this backend definitely - /// does *not* replace, which means their fallback bodies can be MIR-inlined. - fn fallback_intrinsics(&self) -> Vec { - vec![] - } - - /// Is ThinLTO supported by this backend? - fn thin_lto_supported(&self) -> bool { - true - } - /// 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 2737d2ca854a5..d4175ac0100a6 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -17,7 +17,7 @@ use rustc_parse::parser::Recovery; use rustc_query_impl::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; use rustc_session::parse::ParseSess; -use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, EarlySession, Session, lint}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, sym}; use tracing::trace; @@ -357,7 +357,8 @@ pub struct Config { /// hotswapping branch of cg_clif" for "setting the codegen backend from a /// custom driver where the custom codegen backend has arbitrary data." /// (See #102759.) - pub make_codegen_backend: Option Box + Send>>, + pub make_codegen_backend: + Option Box + Send>>, /// The inner atomic value is set to true when a feature marked as `internal` is /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with @@ -409,20 +410,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); - let mut sess = rustc_session::build_session( - config.opts, - CompilerIO { - input: config.input, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, - }, - config.lint_caps, - target, - util::rustc_version_str().unwrap_or("unknown"), - config.ice_file, - config.using_internal_features, - ); + let sess = rustc_session::build_early_session(config.opts, target, config.ice_file); let codegen_backend = match config.make_codegen_backend { None => util::get_codegen_backend( @@ -437,10 +425,20 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se make_codegen_backend(&sess) } }; - codegen_backend.init(&sess); - sess.replaced_intrinsics = FxHashSet::from_iter(codegen_backend.replaced_intrinsics()); - sess.fallback_intrinsics = FxHashSet::from_iter(codegen_backend.fallback_intrinsics()); - sess.thin_lto_supported = codegen_backend.thin_lto_supported(); + let codegen_backend_init = codegen_backend.init(&sess); + let mut sess = rustc_session::build_session( + sess, + codegen_backend_init, + CompilerIO { + input: config.input, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + }, + config.lint_caps, + util::rustc_version_str().unwrap_or("unknown"), + config.using_internal_features, + ); let cfg = parse_cfg(sess.dcx(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6a3e1174a32b2..474870e88f101 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -22,7 +22,10 @@ use rustc_session::config::{ use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib}; -use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, getopts}; +use rustc_session::{ + CodegenBackendInit, CompilerIO, EarlyDiagCtxt, Session, build_early_session, build_session, + getopts, +}; use rustc_span::edition::{DEFAULT_EDITION, Edition}; use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm, sym}; @@ -66,13 +69,13 @@ where static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); + let sess = build_early_session(sessopts, target, None); let sess = build_session( - sessopts, + sess, + CodegenBackendInit::default(), io, Default::default(), - target, "", - None, &USING_INTERNAL_FEATURES, ); let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 40679f12e5ef8..c0af4cb584353 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -36,8 +36,8 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ self, BranchProtection, Cfg, CheckCfg, CoverageLevel, CoverageOptions, CrateType, DebugInfo, - ErrorOutputType, FunctionReturn, Input, InstrumentCoverage, InstrumentMcount, NATIVE_CPU, - OptLevel, OutFileName, OutputType, PAuthKey, PointerAuthOption, SwitchWithOptPath, + ErrorOutputType, FunctionReturn, Input, InstrumentCoverage, InstrumentMcount, LtoCli, + NATIVE_CPU, OptLevel, OutFileName, OutputType, PAuthKey, PointerAuthOption, SwitchWithOptPath, }; use crate::filesearch::FileSearch; use crate::lint::LintId; @@ -322,6 +322,53 @@ impl PointerAuthConfig { } } +/// Partial session built before the full session. More specifically, `EarlySession` is used to +/// build the codegen backend, and then both pieces are used to build the full `Session`. +pub struct EarlySession { + pub target: Target, + pub host: Target, + pub opts: config::Options, + pub psess: ParseSess, +} + +// JUSTIFICATION: defn of the suggested wrapper fns +#[allow(rustc::bad_opt_access)] +impl EarlySession { + #[inline] + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.psess.dcx() + } + + /// Note: this is simpler than `Session::lto`, hence the `early_` prefix (to more clearly + /// distinguish it). + pub fn early_lto(&self) -> LtoCli { + self.opts.cg.lto + } + + pub fn print_llvm_stats(&self) -> bool { + self.opts.unstable_opts.print_codegen_stats + } + + pub fn print_llvm_stats_json(&self) -> Option<&String> { + self.opts.unstable_opts.print_codegen_stats_json.as_ref() + } +} + +/// Some info about the backend, returned by `CodegenBackend::init` and put into the `Session`. +#[derive(Default)] +pub struct CodegenBackendInit { + /// A list of all intrinsics that this backend definitely replaces, which means their fallback + /// bodies do not need to be monomorphized. + pub replaced_intrinsics: Vec, + + /// A list of all intrinsics that this backend definitely does *not* replace, which means their + /// fallback bodies can be MIR-inlined. + pub fallback_intrinsics: Vec, + + /// Is ThinLTO supported by this backend? + pub thin_lto_supported: bool = true, +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -1252,15 +1299,11 @@ fn default_emitter(sopts: &config::Options, source_map: Arc) -> Box, target: Target, - cfg_version: &'static str, ice_file: Option, - using_internal_features: &'static AtomicBool, -) -> Session { +) -> EarlySession { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed // later via the source code. @@ -1295,6 +1338,24 @@ pub fn build_session( dcx.handle().warn(warning) } + let psess = ParseSess::with_dcx(dcx, source_map); + + EarlySession { target, host, opts: sopts, psess } +} + +// JUSTIFICATION: literally session construction +#[allow(rustc::bad_opt_access)] +pub fn build_session( + sess: EarlySession, + codegen_backend_init: CodegenBackendInit, + io: CompilerIO, + driver_lint_caps: FxHashMap, + cfg_version: &'static str, + using_internal_features: &'static AtomicBool, +) -> Session { + let EarlySession { target, host, opts: sopts, psess } = sess; + let dcx = psess.dcx(); + let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile { let directory = if let Some(directory) = d { directory } else { std::path::Path::new(".") }; @@ -1316,8 +1377,6 @@ pub fn build_session( None }; - let psess = ParseSess::with_dcx(dcx, source_map); - let host_triple = config::host_tuple(); let target_triple = sopts.target_triple.tuple(); // FIXME use host sysroot? @@ -1384,9 +1443,9 @@ pub fn build_session( file_depinfo: Default::default(), target_filesearch, host_filesearch, - replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` - fallback_intrinsics: FxHashSet::default(), // filled by `run_compiler` - thin_lto_supported: true, // filled by `run_compiler` + replaced_intrinsics: FxHashSet::from_iter(codegen_backend_init.replaced_intrinsics), + fallback_intrinsics: FxHashSet::from_iter(codegen_backend_init.fallback_intrinsics), + thin_lto_supported: codegen_backend_init.thin_lto_supported, mir_opt_bisect_eval_count: AtomicUsize::new(0), used_features: Lock::default(), removed_rustc_main_attr: AtomicBool::new(false), diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index ae9a64b0abcf4..32c8f50066c8a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -45,7 +45,7 @@ use rustc_log::tracing::debug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, ErrorOutputType, OptLevel}; -use rustc_session::{EarlyDiagCtxt, Session}; +use rustc_session::{EarlyDiagCtxt, EarlySession, Session}; use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; @@ -107,7 +107,7 @@ fn run_many_seeds( /// Generates the codegen backend for code that Miri will interpret: we basically /// use the dummy backend, except that we put the LLVM backend in charge of /// target features. -fn make_miri_codegen_backend(sess: &Session, dep: bool) -> Box { +fn make_miri_codegen_backend(sess: &EarlySession, dep: bool) -> Box { let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format); // Use the target_config method of the default codegen backend (eg LLVM) to ensure the From 1225a52b8d272f3f6600b45e88553011d5d5f7ad Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 19 Aug 2026 17:36:12 +1000 Subject: [PATCH 2/2] Change `CodegenBackend::init` to take `&mut self` It currently takes `&self`, which is a bit strange for an `init` method. As a result, the Cranelift and GCC backends have to use types with interior mutability. This commit changes it to `&mut self`. Benefits: - The Cranelift backend can use `Option` instead of `OnceCell` to indicate uninit vs. init. - The GCC backend can avoid `Mutex`, and use `bool` instead of `AtomicBool`, which makes things much simpler. The commit also restructures `GccCodegenBackend` to mirror `CraneliftCodegenBackend`: just contain an `Option`, which makes the uninit vs. init distinction foolproof. (E.g. no need to set `lto_supported` to false and then later overwrite it with the real value.) As part of this the `LockedTargetInfo` type is renamed `SharedTargetInfo` because that better matches its new internals. (All this compiles both with and without the "master" feature set.) --- compiler/rustc_codegen_cranelift/src/lib.rs | 17 ++- compiler/rustc_codegen_gcc/src/base.rs | 6 +- compiler/rustc_codegen_gcc/src/lib.rs | 109 +++++------------- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- .../rustc_codegen_ssa/src/traits/backend.rs | 2 +- compiler/rustc_interface/src/interface.rs | 2 +- src/tools/miri/src/bin/miri.rs | 2 +- 7 files changed, 47 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 5fff7efeabeee..c2b1490549105 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -31,7 +31,6 @@ extern crate rustc_target; extern crate rustc_driver; use std::any::Any; -use std::cell::OnceCell; use std::env; use std::sync::Arc; @@ -118,7 +117,8 @@ impl String> Drop for PrintOnPanic { } pub struct CraneliftCodegenBackend { - pub config: OnceCell, + // `None` before `init`, `Some` after. + pub config: Option, } impl CodegenBackend for CraneliftCodegenBackend { @@ -126,7 +126,7 @@ impl CodegenBackend for CraneliftCodegenBackend { "cranelift" } - fn init(&self, sess: &EarlySession) -> CodegenBackendInit { + fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit { use rustc_session::config::{InstrumentCoverage, LtoCli}; match (sess.target.requires_lto, sess.early_lto()) { @@ -141,14 +141,13 @@ impl CodegenBackend for CraneliftCodegenBackend { .fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift"); } - let config = self.config.get_or_init(|| { - BackendConfig::from_opts(&sess.opts.cg.llvm_args) - .unwrap_or_else(|err| sess.dcx().fatal(err)) - }); + let config = BackendConfig::from_opts(&sess.opts.cg.llvm_args) + .unwrap_or_else(|err| sess.dcx().fatal(err)); if config.jit_mode && !sess.opts.output_types.should_codegen() { sess.dcx().fatal("JIT mode doesn't work with `cargo check`"); } + self.config = Some(config); CodegenBackendInit { replaced_intrinsics: vec![], @@ -218,7 +217,7 @@ impl CodegenBackend for CraneliftCodegenBackend { fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); - let config = self.config.get().unwrap(); + let config = self.config.as_ref().unwrap(); if config.jit_mode { #[cfg(feature = "jit")] driver::jit::run_jit(tcx, self.target_cpu(tcx.sess), config.jit_args.clone()); @@ -374,5 +373,5 @@ fn build_isa(sess: &Session, jit: bool) -> Arc { /// This is the entrypoint for a hot plugged rustc_codegen_cranelift #[unsafe(no_mangle)] pub fn __rustc_codegen_backend() -> Box { - Box::new(CraneliftCodegenBackend { config: OnceCell::new() }) + Box::new(CraneliftCodegenBackend { config: None }) } diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 14c0fc0958cde..b6058d34c62e2 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -21,7 +21,7 @@ use rustc_target::spec::{Arch, RelocModel}; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::{GccContext, LockedTargetInfo, LtoMode, SyncContext, gcc_util, new_context}; +use crate::{GccContext, LtoMode, SharedTargetInfo, SyncContext, gcc_util, new_context}; #[cfg(feature = "master")] pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility { @@ -73,7 +73,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { pub fn compile_codegen_unit( tcx: TyCtxt<'_>, cgu_name: Symbol, - target_info: LockedTargetInfo, + target_info: SharedTargetInfo, lto_supported: bool, ) -> (ModuleCodegen, u64) { let prof_timer = tcx.prof.generic_activity("codegen_module"); @@ -96,7 +96,7 @@ pub fn compile_codegen_unit( fn module_codegen( tcx: TyCtxt<'_>, cgu_name: Symbol, - target_info: LockedTargetInfo, + target_info: SharedTargetInfo, lto_supported: bool, ) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 87e6c7224471f..c735735b8e953 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -69,12 +69,10 @@ 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}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] @@ -116,7 +114,7 @@ impl String> Drop for PrintOnPanic { #[cfg(not(feature = "master"))] #[derive(Debug)] pub struct TargetInfo { - supports_128bit_integers: AtomicBool, + supports_128bit_integers: bool, } #[cfg(not(feature = "master"))] @@ -128,7 +126,7 @@ impl TargetInfo { fn supports_target_dependent_type(&self, typ: CType) -> bool { match typ { CType::UInt128t | CType::Int128t => { - if self.supports_128bit_integers.load(Ordering::SeqCst) { + if self.supports_128bit_integers { return true; } } @@ -138,43 +136,26 @@ impl TargetInfo { } } +type SharedTargetInfo = Arc>; + #[derive(Clone)] -pub struct LockedTargetInfo { - info: Arc>>>, +pub struct BackendConfig { + target_info: SharedTargetInfo, + lto_supported: bool, } -impl Debug for LockedTargetInfo { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.info.lock().expect("lock").fmt(formatter) - } +#[derive(Clone)] +pub struct GccCodegenBackend { + // `None` before `init`, `Some` after. + pub config: Option, } -impl LockedTargetInfo { - fn cpu_supports(&self, feature: &str) -> bool { - 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") - .as_ref() - .expect("target info not initialized") - .supports_target_dependent_type(typ) +impl GccCodegenBackend { + fn config(&self) -> &BackendConfig { + self.config.as_ref().expect("target info not initialized") } } -#[derive(Clone)] -pub struct GccCodegenBackend { - target_info: LockedTargetInfo, - lto_supported: Arc, -} - fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) { if gccjit::is_loaded() { // Do not load a libgccjit second time. @@ -195,7 +176,7 @@ impl CodegenBackend for GccCodegenBackend { "gcc" } - fn init(&self, sess: &EarlySession) -> CodegenBackendInit { + fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit { fn file_path(sysroot_path: &Path, sess: &EarlySession) -> PathBuf { let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target); @@ -240,14 +221,10 @@ impl CodegenBackend for GccCodegenBackend { context.add_command_line_option(format!("-march={}", target_cpu)); } - *self.target_info.info.lock().expect("lock") = - IntoDynSyncSend(Some(context.get_target_info())); - } - - #[cfg(feature = "master")] - { - let lto_supported = gccjit::is_lto_supported(); - self.lto_supported.store(lto_supported, Ordering::SeqCst); + self.config = Some(BackendConfig { + target_info: Arc::new(IntoDynSyncSend(context.get_target_info())), + lto_supported: gccjit::is_lto_supported(), + }); gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); } @@ -264,15 +241,12 @@ impl CodegenBackend for GccCodegenBackend { gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"), ); - self.target_info - .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); + let target_info = + TargetInfo { supports_128bit_integers: check_context.get_last_error() == Ok(None) }; + self.config = Some(BackendConfig { + target_info: Arc::new(IntoDynSyncSend(target_info)), + lto_supported: false, + }); } CodegenBackendInit { @@ -310,7 +284,7 @@ impl CodegenBackend for GccCodegenBackend { } fn target_config(&self, sess: &Session) -> TargetConfig { - target_config(sess, &self.target_info) + target_config(sess, &self.config().target_info) } } @@ -344,12 +318,11 @@ impl ExtraBackendMethods for GccCodegenBackend { module_name: &str, methods: &[AllocatorMethod], ) -> Self::Module { - let lto_supported = self.lto_supported.load(Ordering::SeqCst); let mut mods = GccContext { context: Arc::new(SyncContext::new(new_context(tcx))), relocation_model: tcx.sess.relocation_model(), lto_mode: LtoMode::None, - lto_supported, + lto_supported: self.config().lto_supported, temp_dir: None, }; @@ -364,12 +337,8 @@ impl ExtraBackendMethods for GccCodegenBackend { tcx: TyCtxt<'_>, cgu_name: Symbol, ) -> (ModuleCodegen, u64) { - base::compile_codegen_unit( - tcx, - cgu_name, - self.target_info.clone(), - self.lto_supported.load(Ordering::SeqCst), - ) + let config = self.config(); + base::compile_codegen_unit(tcx, cgu_name, config.target_info.clone(), config.lto_supported) } } @@ -498,21 +467,7 @@ impl WriteBackendMethods for GccCodegenBackend { /// This is the entrypoint for a hot plugged rustc_codegen_gccjit #[unsafe(no_mangle)] pub fn __rustc_codegen_backend() -> Box { - #[cfg(feature = "master")] - let info = { - // Check whether the target supports 128-bit integers, and sized floating point types (like - // Float16). - Arc::new(Mutex::new(IntoDynSyncSend(None))) - }; - #[cfg(not(feature = "master"))] - 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)), - target_info: LockedTargetInfo { info }, - }) + Box::new(GccCodegenBackend { config: None }) } fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { @@ -529,7 +484,7 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { } /// Returns the features that should be set in `cfg(target_feature)`. -fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { +fn target_config(sess: &Session, target_info: &SharedTargetInfo) -> TargetConfig { let internal_target_features = internal_target_features( sess, |feature| to_gcc_features(sess, feature), diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ca6c68bdc21e4..a652887732b30 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -219,7 +219,7 @@ impl CodegenBackend for LlvmCodegenBackend { "llvm" } - fn init(&self, sess: &EarlySession) -> CodegenBackendInit { + fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit { llvm_util::init(sess); // Make sure llvm is inited // autodiff is based on Enzyme, a library which we might not have available, when it was diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index eed4a48d5e2e8..05ca84c8067f6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -36,7 +36,7 @@ pub trait BackendTypes { pub trait CodegenBackend { fn name(&self) -> &'static str; - fn init(&self, _sess: &EarlySession) -> CodegenBackendInit { + fn init(&mut self, _sess: &EarlySession) -> CodegenBackendInit { Default::default() } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d4175ac0100a6..990d020326279 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -412,7 +412,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let sess = rustc_session::build_early_session(config.opts, target, config.ice_file); - let codegen_backend = match config.make_codegen_backend { + let mut codegen_backend = match config.make_codegen_backend { None => util::get_codegen_backend( &early_dcx, &sess.opts.sysroot, diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 32c8f50066c8a..6a36c04b882f5 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -112,7 +112,7 @@ fn make_miri_codegen_backend(sess: &EarlySession, dep: bool) -> Box