diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index d6c25cf524a5c..f1c16a2795ef9 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -318,7 +318,6 @@ impl WriteBackendMethods for AotDriver { &self, _sess: &Session, _opt_level: OptLevel, - _target_features: &[String], ) -> TargetMachineFactoryFn { Arc::new(|_, _| ()) } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 71fce9e28f120..368878edcc527 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; @@ -43,7 +42,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}; @@ -118,7 +117,8 @@ impl String> Drop for PrintOnPanic { } pub struct CraneliftCodegenBackend { - pub config: OnceCell, + // Set by `init` if not already set. (E.g. by cg_clif.) + pub config: Option, } impl CodegenBackend for CraneliftCodegenBackend { @@ -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(&mut 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 { @@ -140,21 +141,27 @@ 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)) - }); + // Set `config` if not already set. + if self.config.is_none() { + self.config = Some( + 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() { + if self.config.as_ref().unwrap().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 { + global_backend_features: vec![], + replaced_intrinsics: vec![], + fallback_intrinsics: vec![sym::type_id_eq], + thin_lto_supported: false, + } } - fn target_config(&self, sess: &Session) -> TargetConfig { + fn target_config(&self, sess: &EarlySession) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { Arch::X86_64 if sess.target.os != Os::None => { @@ -215,7 +222,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()); @@ -240,10 +247,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. @@ -375,5 +378,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/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index ce1877b308e94..a5cc44a46e154 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -124,7 +124,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( .target_features .iter() .map(|features| features.name.as_str()) - .flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter()) + .flat_map(|feat| to_gcc_features(&cx.tcx.sess.target, feat).into_iter()) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match *x { InstructionSetAttr::ArmA32 => "-thumb-mode", // FIXME(antoyo): support removing feature. InstructionSetAttr::ArmT32 => "thumb-mode", @@ -133,7 +133,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( // FIXME(antoyo): cg_llvm adds global features to each function so that LTO keep them. // Check if GCC requires the same. - let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); + let mut global_features = cx.tcx.sess.global_backend_features.iter().map(|s| s.as_str()); function_features.extend(&mut global_features); let target_features = function_features .iter() diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 7a25fc46fd3fc..a022caf5cf944 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); @@ -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); 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 19fbe37c27b9e..86f1ae1cb5060 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..24f552fed32c6 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -2,18 +2,18 @@ use gccjit::Context; use rustc_codegen_ssa::target_features; use rustc_data_structures::smallvec::{SmallVec, smallvec}; -use rustc_session::Session; +use rustc_session::EarlySession; use rustc_session::config::NATIVE_CPU; -use rustc_target::spec::Arch; +use rustc_target::spec::{Arch, Target}; -fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { +fn gcc_features_by_flags(sess: &EarlySession, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); // FIXME: LLVM also sets +reserve-x18 here under some conditions. } /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). -pub(crate) fn global_gcc_features(sess: &Session) -> Vec { +pub(crate) fn global_gcc_features(sess: &EarlySession) -> Vec { // Features that come earlier are overridden by conflicting features later in the string. // Typically we'll want more explicit settings to override the implicit ones, so: // @@ -40,9 +40,9 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec { // features also work on the command line instead of having two // different names when the GCC name and the Rust name differ. features.extend( - to_gcc_features(sess, feature) + to_gcc_features(&sess.target, feature) .iter() - .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) + .flat_map(|feat| to_gcc_features(&sess.target, feat).into_iter()) .map(|feature| if !enable { format!("-{}", feature) } else { feature.to_string() }), ); }; @@ -59,9 +59,9 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec { } // To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { +pub fn to_gcc_features<'a>(target: &Target, s: &'a str) -> SmallVec<[&'a str; 2]> { // cSpell:disable - match (&sess.target.arch, s) { + match (&target.arch, s) { // FIXME: seems like x87 does not exist? (&Arch::X86 | &Arch::X86_64, "x87") => smallvec![], (&Arch::X86 | &Arch::X86_64, "sse4.2") => smallvec!["sse4.2", "crc32"], @@ -130,7 +130,7 @@ fn handle_native(name: &str) -> &str { unimplemented!(); } -pub fn target_cpu(sess: &Session) -> &str { +pub fn target_cpu(sess: &EarlySession) -> &str { match sess.opts.cg.target_cpu { Some(ref name) => handle_native(name), None => handle_native(sess.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 b3b1bea68e0b4..0121df077f26a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -1351,7 +1351,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..a6ff5a6833044 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")] @@ -93,9 +91,8 @@ use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; 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; @@ -116,7 +113,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 +125,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,41 +135,24 @@ 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) +impl GccCodegenBackend { + fn config(&self) -> &BackendConfig { + self.config.as_ref().expect("target info not initialized") } - - 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) - } -} - -#[derive(Clone)] -pub struct GccCodegenBackend { - target_info: LockedTargetInfo, - lto_supported: Arc, } fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) { @@ -195,8 +175,8 @@ impl CodegenBackend for GccCodegenBackend { "gcc" } - fn init(&self, sess: &Session) { - fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf { + 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); sysroot_path @@ -207,6 +187,8 @@ impl CodegenBackend for GccCodegenBackend { .join("libgccjit.so") } + let global_backend_features = gcc_util::global_gcc_features(sess); + // We use all_paths() instead of only path() in case the path specified by --sysroot is // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. @@ -240,14 +222,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,25 +242,20 @@ 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, + }); } - } - - fn thin_lto_supported(&self) -> bool { - false - } - fn provide(&self, providers: &mut Providers) { - providers.queries.global_backend_features = - |tcx, ()| gcc_util::global_gcc_features(tcx.sess) + CodegenBackendInit { + global_backend_features, + replaced_intrinsics: vec![], + fallback_intrinsics: vec![sym::type_id_eq], + thin_lto_supported: false, + } } fn target_cpu(&self, sess: &Session) -> String { @@ -307,12 +280,8 @@ impl CodegenBackend for GccCodegenBackend { .join(sess, incr_comp_session, crate_info) } - fn target_config(&self, sess: &Session) -> TargetConfig { - target_config(sess, &self.target_info) - } - - fn fallback_intrinsics(&self) -> Vec { - vec![sym::type_id_eq] + fn target_config(&self, sess: &EarlySession) -> TargetConfig { + target_config(sess, &self.config().target_info) } } @@ -346,12 +315,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, }; @@ -366,12 +334,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) } } @@ -429,7 +393,6 @@ impl WriteBackendMethods for GccCodegenBackend { &self, _sess: &Session, _opt_level: OptLevel, - _features: &[String], ) -> TargetMachineFactoryFn { // FIXME(antoyo): set opt level. Arc::new(|_, _| ()) @@ -500,21 +463,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 { @@ -531,10 +480,10 @@ 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: &EarlySession, target_info: &SharedTargetInfo) -> TargetConfig { let internal_target_features = internal_target_features( sess, - |feature| to_gcc_features(sess, feature), + |feature| to_gcc_features(&sess.target, feature), |feature| { // FIXME: we disable Neon for now since we don't support the LLVM intrinsics for it. if feature == "neon" { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 6099e25df4b3e..bbbeacb5dc160 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -499,7 +499,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { template_str.push_str("\n.att_syntax\n"); } - let target_features = self.tcx.global_backend_features(()).join(","); + let target_features = self.tcx.sess.global_backend_features.join(","); let target_cpu = llvm_util::target_cpu(self.tcx.sess); llvm::append_module_inline_asm( diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 9415c2ecb9d10..2af43cc83faf7 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -158,7 +158,7 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>( } if enabled.contains(SanitizerSet::MEMTAG) { // Check to make sure the mte target feature is actually enabled. - let features = tcx.global_backend_features(()); + let features = &tcx.sess.global_backend_features; let mte_feature = features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..])); if let None | Some("-mte") = mte_feature { @@ -425,7 +425,7 @@ pub(crate) fn target_features_attr<'ll, 'tcx>( tcx: TyCtxt<'tcx>, function_features: Vec, ) -> Option<&'ll Attribute> { - let global_features = tcx.global_backend_features(()).iter().map(String::as_str); + let global_features = tcx.sess.global_backend_features.iter().map(String::as_str); let function_features = function_features.iter().map(String::as_str); let target_features = global_features.chain(function_features).intersperse(",").collect::(); @@ -649,7 +649,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = function_features .iter() // Convert to LLVMFeatures and filter out unavailable ones - .flat_map(|feat| llvm_util::to_llvm_features(sess, feat)) + .flat_map(|feat| llvm_util::to_llvm_features(&sess.target, feat)) // Convert LLVMFeatures & dependencies to +s .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}"))) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { diff --git a/compiler/rustc_codegen_llvm/src/back/mod.rs b/compiler/rustc_codegen_llvm/src/back/mod.rs index 6cb89f80ab89a..de6007c17bfff 100644 --- a/compiler/rustc_codegen_llvm/src/back/mod.rs +++ b/compiler/rustc_codegen_llvm/src/back/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod archive; pub(crate) mod lto; +pub(crate) mod owned_mc_subtarget_info; pub(crate) mod owned_target_machine; mod profiling; pub(crate) mod write; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs new file mode 100644 index 0000000000000..6bc346b5acc17 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs @@ -0,0 +1,51 @@ +use std::ffi::CStr; +use std::marker::PhantomData; +use std::ptr::NonNull; + +use rustc_data_structures::small_c_str::SmallCStr; + +use crate::diagnostics::LlvmError; +use crate::llvm; + +/// Responsible for safely creating and disposing llvm::MCSubtargetInfo via ffi functions. +/// Not cloneable as there is no clone function for llvm::MCSubtargetInfo. +pub(crate) struct OwnedMCSubtargetInfo { + info_unique: NonNull, + phantom: PhantomData, +} + +impl OwnedMCSubtargetInfo { + pub(crate) fn new( + triple: &CStr, + cpu: &CStr, + features: &CStr, + ) -> Result> { + // SAFETY: llvm::LLVMRustCreateMCSubtargetInfo copies pointed-to data. + let info_ptr = unsafe { + llvm::LLVMRustCreateMCSubtargetInfo(triple.as_ptr(), cpu.as_ptr(), features.as_ptr()) + }; + + NonNull::new(info_ptr) + .map(|info_unique| Self { info_unique, phantom: PhantomData }) + .ok_or_else(|| LlvmError::CreateMCSubtargetInfo { triple: SmallCStr::from(triple) }) + } + + pub(crate) fn has_feature(&self, feature: &CStr) -> bool { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo`. + unsafe { + llvm::LLVMRustMCSubtargetInfoHasFeature(self.info_unique.as_ref(), feature.as_ptr()) + } + } +} + +impl Drop for OwnedMCSubtargetInfo { + fn drop(&mut self) { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo` and `OwnedMCSubtargetInfo` is not copyable so + // there is no double free or use after free. + unsafe { + llvm::LLVMRustDisposeMCSubtargetInfo(self.info_unique); + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 350d4ce9ee331..20fcbf8b48466 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -41,7 +41,7 @@ impl OwnedTargetMachine { use_wasm_eh: bool, large_data_threshold: u64, ) -> Result> { - // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data + // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed-to data. let tm_ptr = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b8952ffc6bf81..3d66991ac060d 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -100,18 +100,9 @@ fn write_output_file<'ll>( result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } -/// If `for_cfg` is `true` then we are creating this machine for the purpose of populating -/// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration. -/// `-Ctarget-feature` should be ignored in that case since it is already processed separately. -pub(crate) fn create_informational_target_machine( - sess: &Session, - for_cfg: bool, -) -> OwnedTargetMachine { +pub(crate) fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine { let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None }; - // Can't use query system here quite yet because this function is invoked before the query - // system/tcx is set up. - let features = llvm_util::global_llvm_features(sess, for_cfg); - target_machine_factory(sess, config::OptLevel::No, &features)(sess.dcx(), config) + target_machine_factory(sess, config::OptLevel::No)(sess.dcx(), config) } pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine { @@ -129,11 +120,7 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar Some(tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, mod_name)); let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file }; - target_machine_factory( - tcx.sess, - tcx.backend_optimization_level(()), - tcx.global_backend_features(()), - )(tcx.dcx(), config) + target_machine_factory(tcx.sess, tcx.backend_optimization_level(()))(tcx.dcx(), config) } fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) { @@ -195,7 +182,6 @@ fn to_llvm_float_abi(float_abi: Option) -> llvm::FloatAbi { pub(crate) fn target_machine_factory( sess: &Session, optlvl: config::OptLevel, - target_features: &[String], ) -> TargetMachineFactoryFn { // Self-profile timer for creating a _factory_. let _prof_timer = sess.prof.generic_activity("target_machine_factory"); @@ -212,12 +198,11 @@ pub(crate) fn target_machine_factory( let code_model = to_llvm_code_model(sess.code_model()); - // This is used to set cfg_has_threads, so all logic must be in this method. let singlethread = sess.target.singlethread(&sess.internal_target_features); let triple = SmallCStr::new(&versioned_llvm_target(sess)); let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); - let features = CString::new(target_features.join(",")).unwrap(); + let features = CString::new(sess.global_backend_features.join(",")).unwrap(); let abi = SmallCStr::new(sess.target.llvm_abiname.desc()); let trap_unreachable = sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); @@ -255,7 +240,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 853c4bfc9ca3f..fba1a1b746a29 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -228,7 +228,7 @@ pub(crate) unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { - let tm = crate::back::write::create_informational_target_machine(sess, false); + let tm = crate::back::write::create_informational_target_machine(sess); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm.raw()); } @@ -984,9 +984,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/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index fb43b36fe39b9..d20c4fc48a7df 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -119,6 +119,8 @@ pub(crate) enum LlvmError<'a> { WriteOutput { path: &'a Path }, #[diag("could not create LLVM TargetMachine for triple: {$triple}")] CreateTargetMachine { triple: SmallCStr }, + #[diag("could not create LLVM MCSubtargetInfo for triple: {$triple}")] + CreateMCSubtargetInfo { triple: SmallCStr }, #[diag("failed to run LLVM passes")] RunLlvmPasses, #[diag("failed to write LLVM IR to {$path}")] @@ -145,6 +147,9 @@ impl Diagnostic<'_, G> for WithLlvmError<'_> { CreateTargetMachine { .. } => { msg!("could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}") } + CreateMCSubtargetInfo { .. } => { + msg!("could not create LLVM MCSubtargetInfo for triple: {$triple}: {$llvm_err}") + } RunLlvmPasses => msg!("failed to run LLVM passes: {$llvm_err}"), WriteIr { .. } => msg!("failed to write LLVM IR to {$path}: {$llvm_err}"), PrepareThinLtoContext => { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 36709e4ff954f..147ae6cf012b4 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1366,9 +1366,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 a8a8edf98bd86..61a9d3901587a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -37,9 +37,8 @@ use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_metadata::EncodedMetadata; 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}; @@ -130,9 +129,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { &self, sess: &Session, optlvl: OptLevel, - target_features: &[String], ) -> TargetMachineFactoryFn { - back::write::target_machine_factory(sess, optlvl, target_features) + back::write::target_machine_factory(sess, optlvl) } fn optimize_and_codegen_fat_lto( sess: &Session, @@ -219,9 +217,12 @@ impl CodegenBackend for LlvmCodegenBackend { "llvm" } - fn init(&self, sess: &Session) { + fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit { llvm_util::init(sess); // Make sure llvm is inited + let global_backend_features = + llvm_util::global_llvm_features(sess, /* for_cfg */ false); + // autodiff is based on Enzyme, a library which we might not have available, when it was // neither build, nor downloaded via rustup. If autodiff is used, but not available we emit // an early error here and abort compilation. @@ -243,11 +244,57 @@ impl CodegenBackend for LlvmCodegenBackend { enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } } - } - fn provide(&self, providers: &mut Providers) { - providers.queries.global_backend_features = - |tcx, ()| llvm_util::global_llvm_features(tcx.sess, false) + // 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, + sym::integer_max, + sym::integer_min, + + // 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. Adding an intrinsic here can therefore mean the fallback body is used with + // cranelift/GCC even if they have dedicated implementations. + let fallback_intrinsics = vec![sym::type_id_eq]; + + CodegenBackendInit { + global_backend_features, + replaced_intrinsics, + fallback_intrinsics, + thin_lto_supported: true, + } } fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { @@ -321,55 +368,10 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::target_has_mnemonic(sess, mnemonic) } - fn target_config(&self, sess: &Session) -> TargetConfig { + fn target_config(&self, sess: &EarlySession) -> TargetConfig { 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, - sym::integer_max, - sym::integer_min, - - // 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() } @@ -495,7 +497,7 @@ impl ModuleLlvm { ModuleLlvm { llmod_raw, llcx, - tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 684bba7a717db..f72a4c54c1425 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -720,6 +720,7 @@ unsafe extern "C" { pub type TargetMachine; } unsafe extern "C" { + pub(crate) type MCSubtargetInfo; pub(crate) type Twine; pub(crate) type DiagnosticInfo; pub(crate) type SMDiagnostic; @@ -2364,7 +2365,6 @@ unsafe extern "C" { pub(crate) fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); pub(crate) fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); - pub(crate) fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustTargetHasMnemonic(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString); @@ -2406,6 +2406,19 @@ unsafe extern "C" { LargeDataThreshold: u64, ) -> *mut TargetMachine; + pub(crate) fn LLVMRustCreateMCSubtargetInfo( + TripleStr: *const c_char, + CPU: *const c_char, + Features: *const c_char, + ) -> *mut MCSubtargetInfo; + + pub(crate) fn LLVMRustMCSubtargetInfoHasFeature( + MCInfo: &MCSubtargetInfo, + Feature: *const c_char, + ) -> bool; + + pub(crate) fn LLVMRustDisposeMCSubtargetInfo(MCInfo: ptr::NonNull); + pub(crate) fn LLVMRustAddLibraryInfo<'a>( T: &TargetMachine, PM: &PassManager<'a>, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 82ddcca3e1530..544fe609e24a3 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,6 +6,7 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; +use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::target_features::internal_target_features; use rustc_codegen_ssa::{TargetConfig, target_features}; @@ -13,19 +14,20 @@ 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, + Arch, CfgAbi, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport, Target, }; use smallvec::{SmallVec, smallvec}; -use crate::back::write::create_informational_target_machine; +use crate::back::owned_mc_subtarget_info::OwnedMCSubtargetInfo; +use crate::back::write::{create_informational_target_machine, llvm_err}; 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 +45,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); @@ -127,7 +129,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if wants_wasm_eh(sess) { + if wants_wasm_eh(&sess.target) { add("-wasm-enable-eh", false); } @@ -236,9 +238,9 @@ impl<'a> IntoIterator for LLVMFeature<'a> { /// `llvm-project` submodule in Though note that /// Rust can also be build with an external precompiled version of LLVM which might lead to failures /// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics. -pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { +pub(crate) fn to_llvm_features<'a>(target: &Target, s: &'a str) -> Option> { let (major, _, _) = get_version(); - match sess.target.arch { + match target.arch { Arch::AArch64 | Arch::Arm64EC => { match s { "rcpc2" => Some(LLVMFeature::new("rcpc-immo")), @@ -339,13 +341,20 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option TargetConfig { - let target_machine = create_informational_target_machine(sess, true); +pub(crate) fn target_config(sess: &EarlySession) -> TargetConfig { + require_inited(); + let target_features = global_llvm_features(sess, true); + + let triple = SmallCStr::new(&versioned_llvm_target(sess)); + let cpu = SmallCStr::new(target_cpu(sess)); + let features = CString::new(target_features.join(",")).unwrap(); + let mc_subtarget_info = OwnedMCSubtargetInfo::new(&triple, &cpu, &features) + .unwrap_or_else(|err| llvm_err(sess.dcx(), err)); let internal_target_features = internal_target_features( sess, |feature| { - to_llvm_features(sess, feature) + to_llvm_features(&sess.target, feature) .map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter())) .unwrap_or_default() }, @@ -353,14 +362,14 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { // This closure determines whether the target CPU has the feature according to LLVM. We // do *not* consider the `-Ctarget-feature`s here, as that will be handled later in // `internal_target_features`. - if let Some(feat) = to_llvm_features(sess, feature) { + if let Some(feat) = to_llvm_features(&sess.target, feature) { // All the LLVM features this expands to must be enabled. for llvm_feature in feat { let cstr = SmallCStr::new(llvm_feature); - // `LLVMRustHasFeature` is moderately expensive. On targets with many + // `has_feature` is moderately expensive. On targets with many // features (e.g. x86) these calls take a non-trivial fraction of runtime // when compiling very small programs. - if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + if !mc_subtarget_info.has_feature(&cstr) { return false; } } @@ -379,17 +388,17 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { has_reliable_f128_math: true, }; - update_target_reliable_float_cfg(sess, &mut cfg); + update_target_reliable_float_cfg(&sess.target, &mut cfg); cfg } /// Determine whether or not experimental float types are reliable based on known bugs. -fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { - let target_arch = &sess.target.arch; - let target_os = &sess.target.options.os; - let target_env = &sess.target.options.env; - let target_abi = &sess.target.options.cfg_abi; - let target_pointer_width = sess.target.pointer_width; +fn update_target_reliable_float_cfg(target: &Target, cfg: &mut TargetConfig) { + let target_arch = &target.arch; + let target_os = &target.options.os; + let target_env = &target.options.env; + let target_abi = &target.options.cfg_abi; + let target_pointer_width = target.pointer_width; let version = get_version(); let (major, _, _) = version; @@ -501,7 +510,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); match req.kind { PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out), PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out), @@ -519,10 +528,11 @@ fn print_target_cpus(sess: &Session, tm: &llvm::TargetMachine, out: &mut String) cpu_name: &'a str, remark: String, } - // Compare CPU against current target to label the default. + // Compare CPU against current target to label the default. Do not print it if + // `need_explicit_cpu` is set, because in that case the concept of default makes less sense. let target_cpu = handle_native(&sess.target.cpu); let make_remark = |cpu_name| { - if cpu_name == target_cpu { + if cpu_name == target_cpu && !sess.target.need_explicit_cpu { // FIXME(#132514): This prints the LLVM target string, which can be // different from the Rust target string. Is that intended? let target = &sess.target.llvm_target; @@ -576,7 +586,7 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine, out: &mut Str } // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these // strings. - let llvm_feature = to_llvm_features(sess, *feature)?.llvm_feature_name; + let llvm_feature = to_llvm_features(&sess.target, *feature)?.llvm_feature_name; let desc = match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() { Some(index) => { @@ -648,14 +658,14 @@ fn handle_native(cpu_name: &str) -> &str { } } -pub(crate) fn target_cpu(sess: &Session) -> &str { +pub(crate) fn target_cpu(sess: &EarlySession) -> &str { let cpu_name = sess.opts.cg.target_cpu.as_deref().unwrap_or_else(|| &sess.target.cpu); handle_native(cpu_name) } /// 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 { +fn llvm_features_by_flags(sess: &EarlySession, features: &mut Vec) { + if wants_wasm_eh(&sess.target) && sess.panic_strategy() == PanicStrategy::Unwind { features.push("+exception-handling".into()); } @@ -679,7 +689,7 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { /// If `for_cfg` is `true` then we are assembling the feature list for the purpose of populating /// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration. /// `-Ctarget-feature` should be ignored in that case since it is already processed separately. -pub(crate) fn global_llvm_features(sess: &Session, for_cfg: bool) -> Vec { +pub(crate) fn global_llvm_features(sess: &EarlySession, for_cfg: bool) -> Vec { // Features that come earlier are overridden by conflicting features later in the string. // Typically we'll want more explicit settings to override the implicit ones, so: // @@ -738,7 +748,7 @@ pub(crate) fn global_llvm_features(sess: &Session, for_cfg: bool) -> Vec // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - let Some(llvm_feature) = to_llvm_features(sess, feature) else { return }; + let Some(llvm_feature) = to_llvm_features(&sess.target, feature) else { return }; features.extend( std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)).chain( @@ -798,7 +808,7 @@ pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> { pub(crate) fn target_has_mnemonic(sess: &Session, mnemonic: &str) -> bool { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); let cstr = SmallCStr::new(mnemonic); unsafe { llvm::LLVMRustTargetHasMnemonic(tm.raw(), cstr.as_ptr()) } } diff --git a/compiler/rustc_codegen_ssa/src/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs index 68db2d0cbf0bb..5d7c318b0d307 100644 --- a/compiler/rustc_codegen_ssa/src/back/mod.rs +++ b/compiler/rustc_codegen_ssa/src/back/mod.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use rustc_session::Session; +use rustc_session::EarlySession; pub mod apple; pub mod archive; @@ -22,7 +22,7 @@ pub use symbol_export::{exported_non_generic_symbols_helper, reachable_non_gener /// Mach-O commands. /// /// Certain optimizations also depend on the deployment target. -pub fn versioned_llvm_target(sess: &Session) -> Cow<'_, str> { +pub fn versioned_llvm_target(sess: &EarlySession) -> Cow<'_, str> { if sess.target.is_like_darwin { apple::add_version_to_llvm_target(&sess.target.llvm_target, sess.apple_deployment_target()) .into() diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 78cdd3e38f68c..1fe6af0285cb5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -337,7 +337,6 @@ pub struct CodegenContext { pub output_filenames: Arc, pub module_config: Arc, pub opt_level: OptLevel, - pub backend_features: Vec, pub msvc_imps_needed: bool, pub is_pe_coff: bool, pub target_can_use_split_dwarf: bool, @@ -1277,8 +1276,7 @@ fn start_executing_work( }); let opt_level = tcx.backend_optimization_level(()); - let backend_features = tcx.global_backend_features(()).clone(); - let tm_factory = backend.target_machine_factory(tcx.sess, opt_level, &backend_features); + let tm_factory = backend.target_machine_factory(tcx.sess, opt_level); let remark_dir = if let Some(ref dir) = sess.opts.unstable_opts.remark_dir { let result = fs::create_dir_all(dir).and_then(|_| dir.canonicalize()); @@ -1308,7 +1306,6 @@ fn start_executing_work( output_filenames: Arc::clone(tcx.output_filenames(())), module_config: regular_config, opt_level, - backend_features, msvc_imps_needed: msvc_imps_needed(tcx), is_pe_coff: tcx.sess.target.is_like_windows, target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(), @@ -2169,11 +2166,7 @@ impl OngoingCodegen { compiled_modules } MaybeLtoModules::FatLto { cgcx, needs_fat_lto } => { - let tm_factory = self.backend.target_machine_factory( - sess, - cgcx.opt_level, - &cgcx.backend_features, - ); + let tm_factory = self.backend.target_machine_factory(sess, cgcx.opt_level); CompiledModules { modules: vec![do_fat_lto( @@ -2189,11 +2182,7 @@ impl OngoingCodegen { } } MaybeLtoModules::ThinLto { cgcx, needs_thin_lto } => { - let tm_factory = self.backend.target_machine_factory( - sess, - cgcx.opt_level, - &cgcx.backend_features, - ); + let tm_factory = self.backend.target_machine_factory(sess, cgcx.opt_level); CompiledModules { modules: do_thin_lto::( diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 9eb4fd510fd7f..857435bd009ff 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -29,12 +29,11 @@ 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, EntryFnType}; use rustc_span::{DUMMY_SP, Symbol}; use rustc_structures::CrateType; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::spec::{Arch, Os}; +use rustc_target::spec::{Arch, Os, Target as TargetSpec}; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; @@ -373,8 +372,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: &TargetSpec) -> bool { + target.is_like_wasm } /// Returns `true` if this session's target will use SEH-based unwinding. @@ -382,15 +381,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: &TargetSpec) -> 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: &TargetSpec) -> bool { + wants_wasm_eh(target) || wants_msvc_seh(target) } pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( @@ -1047,7 +1046,7 @@ impl CrateInfo { let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, - target_features: tcx.global_backend_features(()).clone(), + target_features: tcx.sess.global_backend_features.clone(), crate_types, exported_symbols, linked_symbols, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index aae300d2f9ed5..99ba7b4360cae 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -504,7 +504,7 @@ fn check_result( } if let Some(features) = check_tied_features( - tcx.sess, + &tcx.sess.target, &codegen_fn_attrs .target_features .iter() diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index bf2ce74e38d84..1272b26ca0612 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -340,7 +340,6 @@ pub fn provide(providers: &mut Providers) { crate::base::provide(&mut providers.queries); crate::target_features::provide(&mut providers.queries); crate::codegen_attrs::provide(&mut providers.queries); - providers.queries.global_backend_features = |_tcx: TyCtxt<'_>, ()| vec![]; } const RLINK_VERSION: u32 = 1; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index afd9a88784c2f..b44a460afcbe2 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. @@ -2177,7 +2177,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, &[]); @@ -2221,7 +2221,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) ); @@ -2251,7 +2251,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, @@ -2317,7 +2317,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 6e87a295e9d2b..19218df78a898 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/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 7dad0cc1732dd..b630155c144ea 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -7,10 +7,10 @@ use rustc_lint_defs::builtin::{AARCH64_SOFTFLOAT_NEON, X86_SOFTFLOAT_SSE}; use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::Session; +use rustc_session::EarlySession; use rustc_session::diagnostics::feature_err; use rustc_span::{Span, Symbol, edit_distance, sym}; -use rustc_target::spec::{Arch, SanitizerSet}; +use rustc_target::spec::{Arch, SanitizerSet, Target}; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; @@ -190,7 +190,7 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, /// features). If the list contains a syntactically invalid item (not starting with `+`/`-`) , the /// error callback is invoked. fn parse_rust_feature_list<'a>( - sess: &'a Session, + target: &'a Target, features: &'a str, err_callback: impl Fn(&'a str), mut callback: impl FnMut( @@ -211,14 +211,14 @@ fn parse_rust_feature_list<'a>( } let features_map = - features_map.get_or_insert_with(|| sess.target.rust_target_features_map()); + features_map.get_or_insert_with(|| target.rust_target_features_map()); if !features_map.contains_key(&base_feature) { callback(base_feature, None, true); continue; } - let implied_features = sess.target.implied_target_features(base_feature, &features_map); + let implied_features = target.implied_target_features(base_feature, &features_map); callback(base_feature, Some(implied_features), true) } else if let Some(base_feature) = feature.strip_prefix('-') { // Skip features that are not target features, but rustc features. @@ -227,7 +227,7 @@ fn parse_rust_feature_list<'a>( } let features_map = - features_map.get_or_insert_with(|| sess.target.rust_target_features_map()); + features_map.get_or_insert_with(|| target.rust_target_features_map()); if !features_map.contains_key(&base_feature) { callback(base_feature, None, false); @@ -240,7 +240,7 @@ fn parse_rust_feature_list<'a>( let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| { let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default(); - for (f, _, is) in sess.target.rust_target_features() { + for (f, _, is) in target.rust_target_features() { for i in is.iter() { set.entry(i).or_default().insert(f); } @@ -282,7 +282,7 @@ fn parse_rust_feature_list<'a>( /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn internal_target_features<'a, const N: usize>( - sess: &Session, + sess: &EarlySession, to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>, mut target_base_has_feature: impl FnMut(&str) -> bool, ) -> UnordSet { @@ -314,7 +314,7 @@ pub fn internal_target_features<'a, const N: usize>( // Add enabled and remove disabled features. parse_rust_feature_list( - sess, + &sess.target, &sess.opts.cg.target_feature, /* err_callback */ |feature| { @@ -402,7 +402,7 @@ pub fn internal_target_features<'a, const N: usize>( }, ); - if let Some(f) = check_tied_features(sess, &enabled_disabled_features) { + if let Some(f) = check_tied_features(&sess.target, &enabled_disabled_features) { sess.dcx().emit_err(diagnostics::TargetFeatureDisableOrEnable { features: f, span: None, @@ -416,11 +416,11 @@ pub fn internal_target_features<'a, const N: usize>( /// Given a map from target_features to whether they are enabled or disabled, ensure only valid /// combinations are allowed. Returns `Some` if a violation is found. pub fn check_tied_features( - sess: &Session, + target: &Target, features: &FxHashMap<&str, bool>, ) -> Option<&'static [&'static str]> { if !features.is_empty() { - for tied in sess.target.tied_target_features() { + for tied in target.tied_target_features() { // Tied features must be set to the same value, or not set at all let mut tied_iter = tied.iter(); let enabled = features.get(tied_iter.next().unwrap()); @@ -437,7 +437,7 @@ pub fn check_tied_features( /// `extend_backend_features` extends the set of backend features (assumed to be in mutable state /// accessible by that closure) to enable/disable the given Rust feature name. pub fn target_spec_to_backend_features<'a>( - sess: &'a Session, + sess: &'a EarlySession, mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool), ) { // This check handles SM versions that defaults (by LLVM) to unsupported (by Rust) PTX ISA versions. @@ -453,7 +453,7 @@ pub fn target_spec_to_backend_features<'a>( // Compute implied features parse_rust_feature_list( - sess, + &sess.target, &sess.target.features, /* err_callback */ |feature| { @@ -476,11 +476,11 @@ pub fn target_spec_to_backend_features<'a>( /// `extend_backend_features` extends the set of backend features (assumed to be in mutable state /// accessible by that closure) to enable/disable the given Rust feature name. pub fn flag_to_backend_features<'a>( - sess: &'a Session, + sess: &'a EarlySession, mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool), ) { parse_rust_feature_list( - sess, + &sess.target, &sess.opts.cg.target_feature, /* err_callback */ |_feature| { @@ -499,7 +499,7 @@ pub fn flag_to_backend_features<'a>( /// Computes the backend target features to be added to account for retpoline flags. /// Used by both LLVM and GCC since their target features are, conveniently, the same. -pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec) { +pub fn retpoline_features_by_flags(sess: &EarlySession, features: &mut Vec) { // -Zretpoline without -Zretpoline-external-thunk enables // retpoline-indirect-branches and retpoline-indirect-calls target features let unstable_opts = &sess.opts.unstable_opts; @@ -518,7 +518,7 @@ pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec) { } /// Computes the backend target features to be added to account for sanitizer flags. -pub fn sanitizer_features_by_flags(sess: &Session, features: &mut Vec) { +pub fn sanitizer_features_by_flags(sess: &EarlySession, features: &mut Vec) { // It's intentional that this is done only for non-kernel version of hwaddress. This matches // clang behavior. if sess.sanitizers().contains(SanitizerSet::HWADDRESS) { diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 11878c1f5165d..96062133b1a49 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::{OutputFilenames, PrintRequest}; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; use rustc_span::Symbol; use rustc_structures::CrateType; @@ -37,13 +37,15 @@ pub trait BackendTypes { pub trait CodegenBackend { fn name(&self) -> &'static str; - fn init(&self, _sess: &Session) {} + fn init(&mut self, _sess: &EarlySession) -> CodegenBackendInit { + Default::default() + } fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} /// Collect target-specific options that should be set in `cfg(...)`, including /// `target_feature` and support for unstable float types. - fn target_config(&self, _sess: &Session) -> TargetConfig { + fn target_config(&self, _sess: &EarlySession) -> TargetConfig { TargetConfig { internal_target_features: Default::default(), // `true` is used as a default so backends need to acknowledge when they do not @@ -71,23 +73,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 @@ -112,6 +97,8 @@ pub trait CodegenBackend { Box::new(crate::back::metadata::DefaultMetadataLoader) } + /// Allows queries to be overridden. Not used by any in-tree backends, but rustc_codegen_spirv + /// and rustc_codegen_nvvm use it. fn provide(&self, _providers: &mut Providers) {} fn target_cpu(&self, sess: &Session) -> String; diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 5bd5b272754b8..bb63e189d20d3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -32,7 +32,6 @@ pub trait WriteBackendMethods: Clone + 'static { &self, sess: &Session, opt_level: config::OptLevel, - target_features: &[String], ) -> TargetMachineFactoryFn; /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index da1f7d2a33967..006a320f11637 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -18,7 +18,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}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, EarlySession, Session}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, sym}; use tracing::trace; @@ -365,7 +365,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 @@ -417,8 +418,27 @@ 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 early_sess = + rustc_session::build_early_session(config.opts, target, config.ice_file); + + let mut codegen_backend = match config.make_codegen_backend { + None => util::get_codegen_backend( + &early_dcx, + &early_sess.opts.sysroot, + early_sess.opts.unstable_opts.codegen_backend.as_deref(), + &early_sess.target, + ), + Some(make_codegen_backend) => { + // N.B. `make_codegen_backend` takes precedence over + // `target.default_codegen_backend`, which is ignored in this case. + make_codegen_backend(&early_sess) + } + }; + let codegen_backend_init = codegen_backend.init(&early_sess); + let mut sess = rustc_session::build_session( - config.opts, + early_sess, + codegen_backend_init, CompilerIO { input: config.input, output_dir: config.output_dir, @@ -426,30 +446,10 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se temps_dir, }, config.lint_caps, - target, util::rustc_version_str().unwrap_or("unknown"), - config.ice_file, config.using_internal_features, ); - let codegen_backend = match config.make_codegen_backend { - None => util::get_codegen_backend( - &early_dcx, - &sess.opts.sysroot, - sess.opts.unstable_opts.codegen_backend.as_deref(), - &sess.target, - ), - Some(make_codegen_backend) => { - // N.B. `make_codegen_backend` takes precedence over - // `target.default_codegen_backend`, which is ignored in this case. - 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 target_config = codegen_backend.target_config(&sess); // Store all of the target features in the session. @@ -463,7 +463,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::add_configuration( &mut sess.config, &target_config, - &sess.target, + &sess.early_sess.target, is_nightly_build, is_crt_static, ); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index d3c479f2a22f5..cf8134a8b49c3 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -21,7 +21,10 @@ use rustc_session::config::{ }; 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, matches.opt_strs("cfg")); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 1af2094c93d0d..b62e5eb0c01fa 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -24,7 +24,7 @@ use rustc_query_impl::{CollectActiveJobsKind, collect_active_query_jobs}; use rustc_session::config::{ Cfg, Jobs, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple, }; -use rustc_session::{EarlyDiagCtxt, IncrCompSession, Session, filesearch}; +use rustc_session::{EarlyDiagCtxt, EarlySession, IncrCompSession, Session, filesearch}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMapInputs; use rustc_span::{SessionGlobals, Symbol, sym}; @@ -379,7 +379,7 @@ impl CodegenBackend for DummyCodegenBackend { "dummy" } - fn target_config(&self, sess: &Session) -> TargetConfig { + fn target_config(&self, sess: &EarlySession) -> TargetConfig { let abi_required_features = sess.target.abi_required_features(); let internal_target_features = internal_target_features::<0>( sess, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index e77d63d91703b..076f40b83a205 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -67,8 +67,10 @@ using namespace llvm; static codegen::RegisterCodeGenFlags CGF; typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; +typedef struct LLVMOpaqueMCSubtargetInfo *LLVMMCSubtargetInfoRef; DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) +DEFINE_STDCXX_CONVERSION_FUNCTIONS(MCSubtargetInfo, LLVMMCSubtargetInfoRef) extern "C" void LLVMRustTimeTraceProfilerInitialize() { timeTraceProfilerInitialize( @@ -89,15 +91,27 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { timeTraceProfilerCleanup(); } -extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, - const char *Feature) { - TargetMachine *Target = unwrap(TM); -#if LLVM_VERSION_GE(23, 0) - const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); -#else - const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); -#endif - return MCInfo.checkFeatures(std::string("+") + Feature); +extern "C" LLVMMCSubtargetInfoRef +LLVMRustCreateMCSubtargetInfo(const char *TripleStr, const char *CPU, + const char *Features) { + std::string Error; + auto Trip = Triple(Triple::normalize(TripleStr)); + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip, Error); + if (TheTarget == nullptr) { + LLVMRustSetLastError(Error.c_str()); + return nullptr; + } + + return wrap(TheTarget->createMCSubtargetInfo(Trip, CPU, Features)); +} + +extern "C" bool LLVMRustMCSubtargetInfoHasFeature(LLVMMCSubtargetInfoRef MCInfo, + const char *Feature) { + return unwrap(MCInfo)->checkFeatures(std::string("+") + Feature); +} + +extern "C" void LLVMRustDisposeMCSubtargetInfo(LLVMMCSubtargetInfoRef MCInfo) { + delete unwrap(MCInfo); } /// Check whether the target has a specific assembly mnemonic like `ret` or diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 5794a6533bd1d..d256aad7d27f2 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2731,14 +2731,6 @@ rustc_queries! { desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 } } - /// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, - /// `--target` and similar). - query global_backend_features(_: ()) -> &'tcx Vec { - arena_cache - eval_always - desc { "computing the backend features for CLI flags" } - } - query check_validity_requirement(key: (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>)) -> Result> { desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f04f40dd17168..62b424fb9c6b3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,4 +1,5 @@ use std::any::Any; +use std::ops::{Deref, DerefMut}; use std::path::Component::Prefix; use std::path::PathBuf; use std::str::FromStr; @@ -37,8 +38,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, 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; @@ -323,16 +324,131 @@ impl PointerAuthConfig { } } +/// Partial session built before the full session. More specifically, `EarlySession` is used to +/// init 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() + } + + #[inline] + pub fn source_map(&self) -> &SourceMap { + self.psess.source_map() + } + + /// 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() + } + + pub fn relocation_model(&self) -> RelocModel { + self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) + } + + pub fn code_model(&self) -> Option { + self.opts.cg.code_model.or(self.target.code_model) + } + + pub fn tls_model(&self) -> TlsModel { + self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) + } + + /// Returns the panic strategy for this compile session. If the user explicitly selected one + /// using '-C panic', use that, otherwise use the panic strategy defined by the target. + pub fn panic_strategy(&self) -> PanicStrategy { + self.opts.cg.panic.unwrap_or(self.target.panic_strategy) + } + + pub fn sanitizers(&self) -> SanitizerSet { + return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers; + } + + /// Get the deployment target on Apple platforms based on the standard environment variables, + /// or fall back to the minimum version supported by `rustc`. + /// + /// This should be guarded behind `if sess.target.is_like_darwin`. + pub fn apple_deployment_target(&self) -> apple::OSVersion { + let min = apple::OSVersion::minimum_deployment_target(&self.target); + let env_var = apple::deployment_target_env_var(&self.target.os); + + // FIXME(madsmtm): Track changes to this. + if let Ok(deployment_target) = env::var(env_var) { + match apple::OSVersion::from_str(&deployment_target) { + Ok(version) => { + let os_min = apple::OSVersion::os_minimum_deployment_target(&self.target.os); + // It is common that the deployment target is set a bit too low, for example on + // macOS Aarch64 to also target older x86_64. So we only want to warn when + // variable is lower than the minimum OS supported by rustc, not when the + // variable is lower than the minimum for a specific target. + if version < os_min { + self.dcx().emit_warn(diagnostics::AppleDeploymentTarget::TooLow { + env_var, + version: version.fmt_pretty().to_string(), + os_min: os_min.fmt_pretty().to_string(), + }); + } + + // Raise the deployment target to the minimum supported. + version.max(min) + } + Err(error) => { + self.dcx() + .emit_err(diagnostics::AppleDeploymentTarget::Invalid { env_var, error }); + min + } + } + } else { + // If no deployment target variable is set, default to the minimum found above. + min + } + } +} + +/// Some info about the backend, returned by `CodegenBackend::init` and put into the `Session`. +#[derive(Default)] +pub struct CodegenBackendInit { + /// See `Session::global_backend_features`. + pub global_backend_features: Vec, + + /// See `Session::replaced_intrinsics`. + pub replaced_intrinsics: Vec, + + /// See `Session::fallback_intrinsics`. + pub fallback_intrinsics: Vec, + + /// See `Session::thin_lto_supported`. + pub thin_lto_supported: bool = true, +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { - pub target: Target, - pub host: Target, + /// The `EarlySession` is embedded so it can be passed to functions that need it. + /// `Session::deref{_,mut}` exist so the fields within can be accessed as if they were direct + /// fields of `Session`. + pub early_sess: EarlySession, pub wasm_proc_macro_tuple: TargetTuple, pub wasm_proc_macro_target: Target, - pub opts: config::Options, pub target_tlib_path: SearchPath, - pub psess: ParseSess, pub unstable_features: UnstableFeatures, pub config: Cfg, pub check_config: CheckCfg, @@ -378,9 +494,15 @@ pub struct Session { /// Set of actually enabled features for the current target, including ones that are not /// in `cfg(target_feature)` because they are unstable or internal-only. /// This is used by the compiler itself when it needs to know which target features are actually - /// going to be enabled in the backend. + /// going to be enabled in the backend (e.g. for knowing which registers inline asm can use). pub internal_target_features: FxIndexSet, + /// The list of backend target features for this session. Not used by Rust itself because the + /// concrete feature names can be backend-specific. This is computed from the target's base + /// features, `-Ctarget-cpu`, `-Ctarget-feature`, and other flags that the current backend + /// models as target features (but that are not considered target features in Rust). + pub global_backend_features: Vec, + /// The version of the rustc process, possibly including a commit hash and description. pub cfg_version: &'static str, @@ -400,11 +522,12 @@ pub struct Session { host_filesearch: Arc, wasm_proc_macro_filesearch: Option>, - /// The names of intrinsics that the current codegen backend replaces - /// with its own implementations. + /// A list of all intrinsics that the current codegen backend definitely replaces with its own + /// implementations, which means their fallback bodies do not need to be monomorphized. pub replaced_intrinsics: FxHashSet, - /// The names of intrinsics that the current codegen backend does *not* replace - /// with its own implementations. + + /// A list of all intrinsics that the current codegen backend definitely does *not* replace + /// with its own implementations, which means their fallback bodies can be MIR-inlined. pub fallback_intrinsics: FxHashSet, /// Does the codegen backend support ThinLTO? @@ -424,6 +547,20 @@ pub struct Session { pub pointer_auth_config: Option, } +impl Deref for Session { + type Target = EarlySession; + + fn deref(&self) -> &EarlySession { + &self.early_sess + } +} + +impl DerefMut for Session { + fn deref_mut(&mut self) -> &mut EarlySession { + &mut self.early_sess + } +} + #[derive(Clone, Copy)] pub enum CodegenUnits { /// Specified by the user. In this case we try fairly hard to produce the @@ -537,16 +674,6 @@ impl Session { self.dcx().set_must_produce_diag() } - #[inline] - pub fn dcx(&self) -> DiagCtxtHandle<'_> { - self.psess.dcx() - } - - #[inline] - pub fn source_map(&self) -> &SourceMap { - self.psess.source_map() - } - pub fn proc_macro_quoted_spans(&self) -> impl Iterator { // This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for // AppendOnlyVec, so we resort to this scheme. @@ -819,14 +946,6 @@ impl Session { self.opts.unstable_opts.verbose_internals } - 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() - } - pub fn verify_llvm_ir(&self) -> bool { self.opts.unstable_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some() } @@ -916,12 +1035,6 @@ impl Session { } } - /// Returns the panic strategy for this compile session. If the user explicitly selected one - /// using '-C panic', use that, otherwise use the panic strategy defined by the target. - pub fn panic_strategy(&self) -> PanicStrategy { - self.opts.cg.panic.unwrap_or(self.target.panic_strategy) - } - pub fn fewer_names(&self) -> bool { if let Some(fewer_names) = self.opts.unstable_opts.fewer_names { fewer_names @@ -954,18 +1067,6 @@ impl Session { self.opts.unstable_opts.contract_checks.unwrap_or(false) } - pub fn relocation_model(&self) -> RelocModel { - self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) - } - - pub fn code_model(&self) -> Option { - self.opts.cg.code_model.or(self.target.code_model) - } - - pub fn tls_model(&self) -> TlsModel { - self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model) - } - pub fn direct_access_external_data(&self) -> Option { self.opts .unstable_opts @@ -1137,50 +1238,6 @@ impl Session { self.opts.cg.link_dead_code.unwrap_or(false) } - /// Get the deployment target on Apple platforms based on the standard environment variables, - /// or fall back to the minimum version supported by `rustc`. - /// - /// This should be guarded behind `if sess.target.is_like_darwin`. - pub fn apple_deployment_target(&self) -> apple::OSVersion { - let min = apple::OSVersion::minimum_deployment_target(&self.target); - let env_var = apple::deployment_target_env_var(&self.target.os); - - // FIXME(madsmtm): Track changes to this. - if let Ok(deployment_target) = env::var(env_var) { - match apple::OSVersion::from_str(&deployment_target) { - Ok(version) => { - let os_min = apple::OSVersion::os_minimum_deployment_target(&self.target.os); - // It is common that the deployment target is set a bit too low, for example on - // macOS Aarch64 to also target older x86_64. So we only want to warn when variable - // is lower than the minimum OS supported by rustc, not when the variable is lower - // than the minimum for a specific target. - if version < os_min { - self.dcx().emit_warn(diagnostics::AppleDeploymentTarget::TooLow { - env_var, - version: version.fmt_pretty().to_string(), - os_min: os_min.fmt_pretty().to_string(), - }); - } - - // Raise the deployment target to the minimum supported. - version.max(min) - } - Err(error) => { - self.dcx() - .emit_err(diagnostics::AppleDeploymentTarget::Invalid { env_var, error }); - min - } - } - } else { - // If no deployment target variable is set, default to the minimum found above. - min - } - } - - pub fn sanitizers(&self) -> SanitizerSet { - return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers; - } - pub fn pointer_authentication(&self) -> bool { self.pointer_auth_config.is_some() } @@ -1254,15 +1311,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. @@ -1297,6 +1350,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( + early_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 } = &early_sess; + let dcx = psess.dcx(); + let wasm_proc_macro_tuple = TargetTuple::from_tuple("wasm32-wasip2"); let (wasm_proc_macro_target, target_warnings) = Target::search( &wasm_proc_macro_tuple, @@ -1331,8 +1402,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? @@ -1385,14 +1454,18 @@ pub fn build_session( let pointer_auth_config: Option = PointerAuthConfig::from_raw(&sopts.unstable_opts.pointer_authentication, &target); + let CodegenBackendInit { + global_backend_features, + replaced_intrinsics, + fallback_intrinsics, + thin_lto_supported, + } = codegen_backend_init; + let sess = Session { - target, - host, + early_sess, wasm_proc_macro_tuple, wasm_proc_macro_target, - opts: sopts, target_tlib_path, - psess, unstable_features: UnstableFeatures::from_environment(None), config: Cfg::default(), check_config: CheckCfg::default(), @@ -1407,6 +1480,7 @@ pub fn build_session( miri_unleashed_features: Lock::new(Default::default()), asm_arch, internal_target_features: Default::default(), + global_backend_features, cfg_version, using_internal_features, env_depinfo: Default::default(), @@ -1414,9 +1488,9 @@ pub fn build_session( target_filesearch, host_filesearch, wasm_proc_macro_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(replaced_intrinsics), + fallback_intrinsics: FxHashSet::from_iter(fallback_intrinsics), + thin_lto_supported, mir_opt_bisect_eval_count: AtomicUsize::new(0), removed_rustc_main_attr: AtomicBool::new(false), pointer_auth_config, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a1c8fd304cd94..f0efba6c8aaac 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2260,11 +2260,12 @@ pub struct TargetOptions { /// Extra arguments to pass to the external assembler (when used) pub asm_args: StaticCow<[StaticCow]>, - /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults - /// to "generic". + /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Must be a name the backend + /// accepts. Defaults to "generic" (which some backends won't accept). pub cpu: StaticCow, - /// Whether a cpu needs to be explicitly set. - /// Set to true if there is no default cpu. Defaults to false. + /// Whether a cpu needs to be explicitly set via `-Ctarget-cpu` for codegen to run. (Even if + /// true, `cpu` is still consulted on non-codegen paths such as cfg/feature computation.) + /// Defaults to false. pub need_explicit_cpu: bool, /// Whether `-Ctarget-cpu` is treated as a target modifier. If this is set /// all crates that are linked together must have been compiled with the diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index 0dcd2428fc703..d4b0bf64206c7 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -14,6 +14,7 @@ pub(crate) fn target() -> Target { pointer_width: 16, options: TargetOptions { c_int_width: 16, + cpu: "avr2".into(), exe_suffix: ".elf".into(), linker: Some("avr-gcc".into()), eh_frame_header: false, diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 9110f6cbf6b4e..01ab675faed8f 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -33,7 +33,7 @@ impl<'sm> HasSourceMap<'sm> for &'sm SourceMap { impl<'sm> HasSourceMap<'sm> for &'sm Session { #[inline] fn source_map(self) -> &'sm SourceMap { - self.source_map() + self.early_sess.source_map() } } impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 19d1f5d6f461c..bf8b684b1fee9 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -46,7 +46,7 @@ use rustc_log::tracing::debug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::TyCtxt; use rustc_session::config::{ErrorOutputType, OptLevel}; -use rustc_session::{EarlyDiagCtxt, Session}; +use rustc_session::{EarlyDiagCtxt, EarlySession, Session}; use rustc_structures::CrateType; use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; @@ -109,12 +109,12 @@ 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 // calculated target features match said backend by respecting eg -Ctarget-cpu. - let native_codegen_backend = rustc_interface::util::get_codegen_backend( + let mut native_codegen_backend = rustc_interface::util::get_codegen_backend( &early_dcx, &sess.opts.sysroot, None, @@ -215,7 +215,7 @@ impl CodegenBackend for MiriCodegenBackend { "miri" } - fn target_config(&self, sess: &Session) -> TargetConfig { + fn target_config(&self, sess: &EarlySession) -> TargetConfig { let native_target_config = self.native.target_config(sess); TargetConfig { internal_target_features: native_target_config.internal_target_features, diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d5de89c0de151..62b28ef84909d 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -14,7 +14,7 @@ use std::collections::HashSet; use std::iter::FromIterator; use std::path::PathBuf; -use run_make_support::{rfs, rustc}; +use run_make_support::{llvm_components_contain, rfs, rustc}; struct PrintCfg { target: &'static str, @@ -73,6 +73,19 @@ fn main() { includes: &["target_has_threads"], disallow: &[], }); + // AVR is experimental, so don't assume it's supported. + if llvm_components_contain("avr") { + check(PrintCfg { + target: "avr-none", + args: &[], + includes: &[ + "target_feature=\"addsubiw\"", + "target_feature=\"ijmpcall\"", + "target_feature=\"lpm\"", + ], + disallow: &[], + }); + } } fn check(PrintCfg { target, args, includes, disallow }: PrintCfg) { diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 6c88f3164e9e4..4deb7c9bfcc93 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -95,5 +95,10 @@ fn main() { .crate_type("lib") .arg("-Ctarget-cpu=generic") .run(); - rustc().arg("-Zunstable-options").target("require-explicit-cpu").print("target-cpus").run(); + rustc() + .arg("-Zunstable-options") + .target("require-explicit-cpu") + .print("target-cpus") + .run() + .assert_stdout_not_contains("default target CPU"); } diff --git a/tests/ui/abi/avr-sram.rs b/tests/ui/abi/avr-sram.rs index 0266f7d6b22ca..7b8ec5ee8fa0c 100644 --- a/tests/ui/abi/avr-sram.rs +++ b/tests/ui/abi/avr-sram.rs @@ -1,12 +1,25 @@ -//@ revisions: has_sram no_sram disable_sram -//@ build-pass +//@ revisions: has_sram no_sram disable_sram default_cpu +// +//@[has_sram] build-pass //@[has_sram] compile-flags: --target avr-none -C target-cpu=atmega328p //@[has_sram] needs-llvm-components: avr +// +//@[no_sram] build-pass //@[no_sram] compile-flags: --target avr-none -C target-cpu=attiny11 //@[no_sram] needs-llvm-components: avr +// +//@[disable_sram] build-pass //@[disable_sram] compile-flags: --target avr-none -C target-cpu=atmega328p -C target-feature=-sram //@[disable_sram] needs-llvm-components: avr +// +// Note: this revision relies on `need_explicit_cpu` only being enforced at codegen, which is why +// it uses `check-pass` instead of `build-pass`. +//@[default_cpu] check-pass +//@[default_cpu] compile-flags: --target avr-none +//@[default_cpu] needs-llvm-components: avr +// //@ ignore-backends: gcc +// //[no_sram,disable_sram]~? WARN target feature `sram` must be enabled //[disable_sram]~? WARN target feature `sram` cannot be disabled with `-Ctarget-feature` diff --git a/tests/ui/codegen/custom-target-invalid-llvm-target.rs b/tests/ui/codegen/custom-target-invalid-llvm-target.rs index 72c80cd7af4f1..d90b56c5d13c0 100644 --- a/tests/ui/codegen/custom-target-invalid-llvm-target.rs +++ b/tests/ui/codegen/custom-target-invalid-llvm-target.rs @@ -7,4 +7,4 @@ fn main() {} -//~? ERROR failed to parse target machine config to target machine +//~? ERROR could not create LLVM MCSubtargetInfo for triple: not-a-real-target diff --git a/tests/ui/codegen/custom-target-invalid-llvm-target.stderr b/tests/ui/codegen/custom-target-invalid-llvm-target.stderr index d5ac437a2b646..e2e844fa1bce7 100644 --- a/tests/ui/codegen/custom-target-invalid-llvm-target.stderr +++ b/tests/ui/codegen/custom-target-invalid-llvm-target.stderr @@ -1,2 +1,2 @@ -error: failed to parse target machine config to target machine: could not create LLVM TargetMachine for triple: not-a-real-target +error: could not create LLVM MCSubtargetInfo for triple: not-a-real-target: No available targets are compatible with triple "not-a-real-target"