From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_middle/src/mir/mono.rs | 527 ++++++++++++++++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 compiler/rustc_middle/src/mir/mono.rs (limited to 'compiler/rustc_middle/src/mir/mono.rs') diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs new file mode 100644 index 000000000..21ae121e1 --- /dev/null +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -0,0 +1,527 @@ +use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; +use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; +use rustc_attr::InlineAttr; +use rustc_data_structures::base_n; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::ItemId; +use rustc_index::vec::Idx; +use rustc_query_system::ich::StableHashingContext; +use rustc_session::config::OptLevel; +use rustc_span::source_map::Span; +use rustc_span::symbol::Symbol; +use std::fmt; +use std::hash::Hash; + +/// Describes how a monomorphization will be instantiated in object files. +#[derive(PartialEq)] +pub enum InstantiationMode { + /// There will be exactly one instance of the given MonoItem. It will have + /// external linkage so that it can be linked to from other codegen units. + GloballyShared { + /// In some compilation scenarios we may decide to take functions that + /// are typically `LocalCopy` and instead move them to `GloballyShared` + /// to avoid codegenning them a bunch of times. In this situation, + /// however, our local copy may conflict with other crates also + /// inlining the same function. + /// + /// This flag indicates that this situation is occurring, and informs + /// symbol name calculation that some extra mangling is needed to + /// avoid conflicts. Note that this may eventually go away entirely if + /// ThinLTO enables us to *always* have a globally shared instance of a + /// function within one crate's compilation. + may_conflict: bool, + }, + + /// Each codegen unit containing a reference to the given MonoItem will + /// have its own private copy of the function (with internal linkage). + LocalCopy, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)] +pub enum MonoItem<'tcx> { + Fn(Instance<'tcx>), + Static(DefId), + GlobalAsm(ItemId), +} + +impl<'tcx> MonoItem<'tcx> { + /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). + pub fn is_user_defined(&self) -> bool { + match *self { + MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, + } + } + + pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize { + match *self { + MonoItem::Fn(instance) => { + // Estimate the size of a function based on how many statements + // it contains. + tcx.instance_def_size_estimate(instance.def) + } + // Conservatively estimate the size of a static declaration + // or assembly to be 1. + MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, + } + } + + pub fn is_generic_fn(&self) -> bool { + match *self { + MonoItem::Fn(ref instance) => instance.substs.non_erasable_generics().next().is_some(), + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false, + } + } + + pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> SymbolName<'tcx> { + match *self { + MonoItem::Fn(instance) => tcx.symbol_name(instance), + MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)), + MonoItem::GlobalAsm(item_id) => { + SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id)) + } + } + } + + pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { + let generate_cgu_internal_copies = tcx + .sess + .opts + .unstable_opts + .inline_in_all_cgus + .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) + && !tcx.sess.link_dead_code(); + + match *self { + MonoItem::Fn(ref instance) => { + let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id); + // If this function isn't inlined or otherwise has an extern + // indicator, then we'll be creating a globally shared version. + if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() + || !instance.def.generates_cgu_internal_copy(tcx) + || Some(instance.def_id()) == entry_def_id + { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + + // At this point we don't have explicit linkage and we're an + // inlined function. If we're inlining into all CGUs then we'll + // be creating a local copy per CGU. + if generate_cgu_internal_copies { + return InstantiationMode::LocalCopy; + } + + // Finally, if this is `#[inline(always)]` we're sure to respect + // that with an inline copy per CGU, but otherwise we'll be + // creating one copy of this `#[inline]` function which may + // conflict with upstream crates as it could be an exported + // symbol. + match tcx.codegen_fn_attrs(instance.def_id()).inline { + InlineAttr::Always => InstantiationMode::LocalCopy, + _ => InstantiationMode::GloballyShared { may_conflict: true }, + } + } + MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { + InstantiationMode::GloballyShared { may_conflict: false } + } + } + } + + pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { + let def_id = match *self { + MonoItem::Fn(ref instance) => instance.def_id(), + MonoItem::Static(def_id) => def_id, + MonoItem::GlobalAsm(..) => return None, + }; + + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + codegen_fn_attrs.linkage + } + + /// Returns `true` if this instance is instantiable - whether it has no unsatisfied + /// predicates. + /// + /// In order to codegen an item, all of its predicates must hold, because + /// otherwise the item does not make sense. Type-checking ensures that + /// the predicates of every item that is *used by* a valid item *do* + /// hold, so we can rely on that. + /// + /// However, we codegen collector roots (reachable items) and functions + /// in vtables when they are seen, even if they are not used, and so they + /// might not be instantiable. For example, a programmer can define this + /// public function: + /// + /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone { + /// <&mut () as Clone>::clone(&s); + /// } + /// + /// That function can't be codegened, because the method `<&mut () as Clone>::clone` + /// does not exist. Luckily for us, that function can't ever be used, + /// because that would require for `&'a mut (): Clone` to hold, so we + /// can just not emit any code, or even a linker reference for it. + /// + /// Similarly, if a vtable method has such a signature, and therefore can't + /// be used, we can just not emit it and have a placeholder (a null pointer, + /// which will never be accessed) in its place. + pub fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool { + debug!("is_instantiable({:?})", self); + let (def_id, substs) = match *self { + MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), + MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()), + // global asm never has predicates + MonoItem::GlobalAsm(..) => return true, + }; + + !tcx.subst_and_check_impossible_predicates((def_id, &substs)) + } + + pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { + match *self { + MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(), + MonoItem::Static(def_id) => def_id.as_local(), + MonoItem::GlobalAsm(item_id) => Some(item_id.def_id), + } + .map(|def_id| tcx.def_span(def_id)) + } + + // Only used by rustc_codegen_cranelift + pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { + crate::dep_graph::make_compile_mono_item(tcx, self) + } + + /// Returns the item's `CrateNum` + pub fn krate(&self) -> CrateNum { + match self { + MonoItem::Fn(ref instance) => instance.def_id().krate, + MonoItem::Static(def_id) => def_id.krate, + MonoItem::GlobalAsm(..) => LOCAL_CRATE, + } + } +} + +impl<'tcx> fmt::Display for MonoItem<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + MonoItem::Fn(instance) => write!(f, "fn {}", instance), + MonoItem::Static(def_id) => { + write!(f, "static {}", Instance::new(def_id, InternalSubsts::empty())) + } + MonoItem::GlobalAsm(..) => write!(f, "global_asm"), + } + } +} + +#[derive(Debug)] +pub struct CodegenUnit<'tcx> { + /// A name for this CGU. Incremental compilation requires that + /// name be unique amongst **all** crates. Therefore, it should + /// contain something unique to this crate (e.g., a module path) + /// as well as the crate name and disambiguator. + name: Symbol, + items: FxHashMap, (Linkage, Visibility)>, + size_estimate: Option, + primary: bool, + /// True if this is CGU is used to hold code coverage information for dead code, + /// false otherwise. + is_code_coverage_dead_code_cgu: bool, +} + +/// Specifies the linkage type for a `MonoItem`. +/// +/// See for more details about these variants. +#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] +pub enum Linkage { + External, + AvailableExternally, + LinkOnceAny, + LinkOnceODR, + WeakAny, + WeakODR, + Appending, + Internal, + Private, + ExternalWeak, + Common, +} + +#[derive(Copy, Clone, PartialEq, Debug, HashStable)] +pub enum Visibility { + Default, + Hidden, + Protected, +} + +impl<'tcx> CodegenUnit<'tcx> { + #[inline] + pub fn new(name: Symbol) -> CodegenUnit<'tcx> { + CodegenUnit { + name, + items: Default::default(), + size_estimate: None, + primary: false, + is_code_coverage_dead_code_cgu: false, + } + } + + pub fn name(&self) -> Symbol { + self.name + } + + pub fn set_name(&mut self, name: Symbol) { + self.name = name; + } + + pub fn is_primary(&self) -> bool { + self.primary + } + + pub fn make_primary(&mut self) { + self.primary = true; + } + + pub fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + &self.items + } + + pub fn items_mut(&mut self) -> &mut FxHashMap, (Linkage, Visibility)> { + &mut self.items + } + + pub fn is_code_coverage_dead_code_cgu(&self) -> bool { + self.is_code_coverage_dead_code_cgu + } + + /// Marks this CGU as the one used to contain code coverage information for dead code. + pub fn make_code_coverage_dead_code_cgu(&mut self) { + self.is_code_coverage_dead_code_cgu = true; + } + + pub fn mangle_name(human_readable_name: &str) -> String { + // We generate a 80 bit hash from the name. This should be enough to + // avoid collisions and is still reasonably short for filenames. + let mut hasher = StableHasher::new(); + human_readable_name.hash(&mut hasher); + let hash: u128 = hasher.finish(); + let hash = hash & ((1u128 << 80) - 1); + base_n::encode(hash, base_n::CASE_INSENSITIVE) + } + + pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) { + // Estimate the size of a codegen unit as (approximately) the number of MIR + // statements it corresponds to. + self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); + } + + #[inline] + pub fn size_estimate(&self) -> usize { + // Should only be called if `estimate_size` has previously been called. + self.size_estimate.expect("estimate_size must be called before getting a size_estimate") + } + + pub fn modify_size_estimate(&mut self, delta: usize) { + assert!(self.size_estimate.is_some()); + if let Some(size_estimate) = self.size_estimate { + self.size_estimate = Some(size_estimate + delta); + } + } + + pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { + self.items().contains_key(item) + } + + pub fn work_product_id(&self) -> WorkProductId { + WorkProductId::from_cgu_name(self.name().as_str()) + } + + pub fn previous_work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct { + let work_product_id = self.work_product_id(); + tcx.dep_graph + .previous_work_product(&work_product_id) + .unwrap_or_else(|| panic!("Could not find work-product for CGU `{}`", self.name())) + } + + pub fn items_in_deterministic_order( + &self, + tcx: TyCtxt<'tcx>, + ) -> Vec<(MonoItem<'tcx>, (Linkage, Visibility))> { + // The codegen tests rely on items being process in the same order as + // they appear in the file, so for local items, we sort by node_id first + #[derive(PartialEq, Eq, PartialOrd, Ord)] + pub struct ItemSortKey<'tcx>(Option, SymbolName<'tcx>); + + fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> { + ItemSortKey( + match item { + MonoItem::Fn(ref instance) => { + match instance.def { + // We only want to take HirIds of user-defined + // instances into account. The others don't matter for + // the codegen tests and can even make item order + // unstable. + InstanceDef::Item(def) => def.did.as_local().map(Idx::index), + InstanceDef::VTableShim(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::Intrinsic(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::CloneShim(..) => None, + } + } + MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), + MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.index()), + }, + item.symbol_name(tcx), + ) + } + + let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); + items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); + items + } + + pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { + crate::dep_graph::make_compile_codegen_unit(tcx, self.name()) + } +} + +impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + let CodegenUnit { + ref items, + name, + // The size estimate is not relevant to the hash + size_estimate: _, + primary: _, + is_code_coverage_dead_code_cgu, + } = *self; + + name.hash_stable(hcx, hasher); + is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher); + + let mut items: Vec<(Fingerprint, _)> = items + .iter() + .map(|(mono_item, &attrs)| { + let mut hasher = StableHasher::new(); + mono_item.hash_stable(hcx, &mut hasher); + let mono_item_fingerprint = hasher.finish(); + (mono_item_fingerprint, attrs) + }) + .collect(); + + items.sort_unstable_by_key(|i| i.0); + items.hash_stable(hcx, hasher); + } +} + +pub struct CodegenUnitNameBuilder<'tcx> { + tcx: TyCtxt<'tcx>, + cache: FxHashMap, +} + +impl<'tcx> CodegenUnitNameBuilder<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + CodegenUnitNameBuilder { tcx, cache: Default::default() } + } + + /// CGU names should fulfill the following requirements: + /// - They should be able to act as a file name on any kind of file system + /// - They should not collide with other CGU names, even for different versions + /// of the same crate. + /// + /// Consequently, we don't use special characters except for '.' and '-' and we + /// prefix each name with the crate-name and crate-disambiguator. + /// + /// This function will build CGU names of the form: + /// + /// ```text + /// .[-in-](-)*[.] + /// = . + /// ``` + /// + /// The '.' before `` makes sure that names with a special + /// suffix can never collide with a name built out of regular Rust + /// identifiers (e.g., module paths). + pub fn build_cgu_name( + &mut self, + cnum: CrateNum, + components: I, + special_suffix: Option, + ) -> Symbol + where + I: IntoIterator, + C: fmt::Display, + S: fmt::Display, + { + let cgu_name = self.build_cgu_name_no_mangle(cnum, components, special_suffix); + + if self.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + cgu_name + } else { + Symbol::intern(&CodegenUnit::mangle_name(cgu_name.as_str())) + } + } + + /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the + /// resulting name. + pub fn build_cgu_name_no_mangle( + &mut self, + cnum: CrateNum, + components: I, + special_suffix: Option, + ) -> Symbol + where + I: IntoIterator, + C: fmt::Display, + S: fmt::Display, + { + use std::fmt::Write; + + let mut cgu_name = String::with_capacity(64); + + // Start out with the crate name and disambiguator + let tcx = self.tcx; + let crate_prefix = self.cache.entry(cnum).or_insert_with(|| { + // Whenever the cnum is not LOCAL_CRATE we also mix in the + // local crate's ID. Otherwise there can be collisions between CGUs + // instantiating stuff for upstream crates. + let local_crate_id = if cnum != LOCAL_CRATE { + let local_stable_crate_id = tcx.sess.local_stable_crate_id(); + format!( + "-in-{}.{:08x}", + tcx.crate_name(LOCAL_CRATE), + local_stable_crate_id.to_u64() as u32, + ) + } else { + String::new() + }; + + let stable_crate_id = tcx.sess.local_stable_crate_id(); + format!( + "{}.{:08x}{}", + tcx.crate_name(cnum), + stable_crate_id.to_u64() as u32, + local_crate_id, + ) + }); + + write!(cgu_name, "{}", crate_prefix).unwrap(); + + // Add the components + for component in components { + write!(cgu_name, "-{}", component).unwrap(); + } + + if let Some(special_suffix) = special_suffix { + // We add a dot in here so it cannot clash with anything in a regular + // Rust identifier + write!(cgu_name, ".{}", special_suffix).unwrap(); + } + + Symbol::intern(&cgu_name) + } +} -- cgit v1.2.3