diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_monomorphize | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_monomorphize')
-rw-r--r-- | compiler/rustc_monomorphize/Cargo.toml | 2 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/messages.ftl | 34 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/collector.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/lib.rs | 12 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/partitioning/default.rs | 170 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/partitioning/merging.rs | 111 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/partitioning/mod.rs | 197 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/polymorphize.rs | 12 | ||||
-rw-r--r-- | compiler/rustc_monomorphize/src/util.rs | 4 |
9 files changed, 299 insertions, 253 deletions
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index c8af10576..6d3a3bf90 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -8,11 +8,11 @@ edition = "2021" [dependencies] serde = "1" serde_json = "1" -smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] } tracing = "0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 6cea6a603..fdd47e6f7 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,32 +1,32 @@ -monomorphize_recursion_limit = - reached the recursion limit while instantiating `{$shrunk}` - .note = `{$def_path_str}` defined here - -monomorphize_written_to_path = the full type name has been written to '{$path}' - -monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` - monomorphize_consider_type_length_limit = consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate -monomorphize_fatal_error = {$error_message} - -monomorphize_unknown_partition_strategy = unknown partitioning strategy +monomorphize_couldnt_dump_mono_stats = + unexpected error occurred while dumping monomorphization stats: {$error} -monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined +monomorphize_encountered_error_while_instantiating = + the above error was encountered while instantiating `{$formatted_item}` -monomorphize_unused_generic_params = item has unused generic parameters +monomorphize_fatal_error = {$error_message} monomorphize_large_assignments = moving {$size} bytes .label = value moved from here .note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` -monomorphize_couldnt_dump_mono_stats = - unexpected error occurred while dumping monomorphization stats: {$error} +monomorphize_recursion_limit = + reached the recursion limit while instantiating `{$shrunk}` + .note = `{$def_path_str}` defined here -monomorphize_encountered_error_while_instantiating = - the above error was encountered while instantiating `{$formatted_item}` +monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined + +monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` monomorphize_unknown_cgu_collection_mode = unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode + +monomorphize_unknown_partition_strategy = unknown partitioning strategy + +monomorphize_unused_generic_params = item has unused generic parameters + +monomorphize_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 7bcff7e07..35b154b7b 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -185,9 +185,9 @@ use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, @@ -402,7 +402,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< } /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a -/// post-monorphization error is encountered during a collection step. +/// post-monomorphization error is encountered during a collection step. #[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")] fn collect_items_rec<'tcx>( tcx: TyCtxt<'tcx>, @@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - value, + ty::EarlyBinder(value), ) } } @@ -843,7 +843,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } } mir::TerminatorKind::Assert { ref msg, .. } => { - let lang_item = match msg { + let lang_item = match &**msg { mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck, _ => LangItem::Panic, }; @@ -1230,7 +1230,7 @@ impl<'v> RootCollector<'_, 'v> { DefKind::GlobalAsm => { debug!( "RootCollector: ItemKind::GlobalAsm({})", - self.tcx.def_path_str(id.owner_id.to_def_id()) + self.tcx.def_path_str(id.owner_id) ); self.output.push(dummy_spanned(MonoItem::GlobalAsm(id))); } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5000fb719..ecc50c3f6 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -10,11 +10,11 @@ extern crate tracing; extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; -use rustc_macros::fluent_messages; +use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::query::{Providers, TyCtxtAt}; use rustc_middle::ty::{self, Ty}; mod collector; @@ -30,8 +30,12 @@ fn custom_coerce_unsize_info<'tcx>( source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> CustomCoerceUnsized { - let trait_ref = - ty::Binder::dummy(tcx.mk_trait_ref(LangItem::CoerceUnsized, [source_ty, target_ty])); + let trait_ref = ty::Binder::dummy(ty::TraitRef::from_lang_item( + tcx.tcx, + LangItem::CoerceUnsized, + tcx.span, + [source_ty, target_ty], + )); match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 482b78d42..603b3ddc1 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -1,3 +1,4 @@ +use std::cmp; use std::collections::hash_map::Entry; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -14,19 +15,19 @@ use rustc_span::symbol::Symbol; use super::PartitioningCx; use crate::collector::InliningMap; -use crate::partitioning::merging; -use crate::partitioning::{ - MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning, -}; +use crate::partitioning::{MonoItemPlacement, Partition, PlacedRootMonoItems}; pub struct DefaultPartitioning; -impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { - fn place_root_mono_items( +impl<'tcx> Partition<'tcx> for DefaultPartitioning { + fn place_root_mono_items<I>( &mut self, cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, - ) -> PreInliningPartitioning<'tcx> { + mono_items: &mut I, + ) -> PlacedRootMonoItems<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>, + { let mut roots = FxHashSet::default(); let mut codegen_units = FxHashMap::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); @@ -88,38 +89,120 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name)); } - PreInliningPartitioning { - codegen_units: codegen_units.into_values().map(|codegen_unit| codegen_unit).collect(), - roots, - internalization_candidates, - } + let codegen_units = codegen_units.into_values().collect(); + PlacedRootMonoItems { codegen_units, roots, internalization_candidates } } fn merge_codegen_units( &mut self, cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, + codegen_units: &mut Vec<CodegenUnit<'tcx>>, ) { - merging::merge_codegen_units(cx, initial_partitioning); + assert!(cx.target_cgu_count >= 1); + + // Note that at this point in time the `codegen_units` here may not be + // in a deterministic order (but we know they're deterministically the + // same set). We want this merging to produce a deterministic ordering + // of codegen units from the input. + // + // Due to basically how we've implemented the merging below (merge the + // two smallest into each other) we're sure to start off with a + // deterministic order (sorted by name). This'll mean that if two cgus + // have the same size the stable sort below will keep everything nice + // and deterministic. + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + + // This map keeps track of what got merged into what. + let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = + codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); + + // Merge the two smallest codegen units until the target size is + // reached. + while codegen_units.len() > cx.target_cgu_count { + // Sort small cgus to the back + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); + let mut smallest = codegen_units.pop().unwrap(); + let second_smallest = codegen_units.last_mut().unwrap(); + + // Move the mono-items from `smallest` to `second_smallest` + second_smallest.modify_size_estimate(smallest.size_estimate()); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); + } + + // Record that `second_smallest` now contains all the stuff that was + // in `smallest` before. + let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); + cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); + + debug!( + "CodegenUnit {} merged into CodegenUnit {}", + smallest.name(), + second_smallest.name() + ); + } + + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); + + if cx.tcx.sess.opts.incremental.is_some() { + // If we are doing incremental compilation, we want CGU names to + // reflect the path of the source level module they correspond to. + // For CGUs that contain the code of multiple modules because of the + // merging done above, we use a concatenation of the names of all + // contained CGUs. + let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents + .into_iter() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = + cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (current_cgu_name, cgu_contents.join("--")) + }) + .collect(); + + for cgu in codegen_units.iter_mut() { + if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { + if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { + cgu.set_name(Symbol::intern(&new_cgu_name)); + } else { + // If we don't require CGU names to be human-readable, + // we use a fixed length hash of the composite CGU name + // instead. + let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); + cgu.set_name(Symbol::intern(&new_cgu_name)); + } + } + } + } else { + // If we are compiling non-incrementally we just generate simple CGU + // names containing an index. + for (index, cgu) in codegen_units.iter_mut().enumerate() { + let numbered_codegen_unit_name = + cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)); + cgu.set_name(numbered_codegen_unit_name); + } + } } fn place_inlined_mono_items( &mut self, cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx> { - let mut new_partitioning = Vec::new(); + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet<MonoItem<'tcx>>, + ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> { let mut mono_item_placements = FxHashMap::default(); - let PreInliningPartitioning { - codegen_units: initial_cgus, - roots, - internalization_candidates, - } = initial_partitioning; - - let single_codegen_unit = initial_cgus.len() == 1; + let single_codegen_unit = codegen_units.len() == 1; - for old_codegen_unit in initial_cgus { + for old_codegen_unit in codegen_units.iter_mut() { // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { @@ -171,14 +254,10 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { } } - new_partitioning.push(new_codegen_unit); + *old_codegen_unit = new_codegen_unit; } - return PostInliningPartitioning { - codegen_units: new_partitioning, - mono_item_placements, - internalization_candidates, - }; + return mono_item_placements; fn follow_inlining<'tcx>( mono_item: MonoItem<'tcx>, @@ -198,14 +277,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn internalize_symbols( &mut self, cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, ) { - if partitioning.codegen_units.len() == 1 { + if codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we // can internalize all candidates, since there is nowhere else they // could be accessed from. - for cgu in &mut partitioning.codegen_units { - for candidate in &partitioning.internalization_candidates { + for cgu in codegen_units { + for candidate in &internalization_candidates { cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); } } @@ -222,15 +303,13 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { } }); - let mono_item_placements = &partitioning.mono_item_placements; - // For each internalization candidates in each codegen unit, check if it is // accessed from outside its defining codegen unit. - for cgu in &mut partitioning.codegen_units { + for cgu in codegen_units { let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; for (accessee, linkage_and_visibility) in cgu.items_mut() { - if !partitioning.internalization_candidates.contains(accessee) { + if !internalization_candidates.contains(accessee) { // This item is no candidate for internalizing, so skip it. continue; } @@ -267,7 +346,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { - ty::InstanceDef::Item(def) => def.did, + ty::InstanceDef::Item(def) => def, ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) @@ -302,12 +381,12 @@ fn characteristic_def_id_of_mono_item<'tcx>( // When polymorphization is enabled, methods which do not depend on their generic // parameters, but the self-type of their impl block do will fail to normalize. - if !tcx.sess.opts.unstable_opts.polymorphize || !instance.needs_subst() { + if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() { // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - tcx.type_of(impl_def_id).skip_binder(), + tcx.type_of(impl_def_id), ); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); @@ -421,10 +500,9 @@ fn mono_item_visibility<'tcx>( }; let def_id = match instance.def { - InstanceDef::Item(def) => def.did, - InstanceDef::DropGlue(def_id, Some(_)) => def_id, + InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, - // We match the visiblity of statics here + // We match the visibility of statics here InstanceDef::ThreadLocalShim(def_id) => { return static_visibility(tcx, can_be_internalized, def_id); } diff --git a/compiler/rustc_monomorphize/src/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs deleted file mode 100644 index 5c524a184..000000000 --- a/compiler/rustc_monomorphize/src/partitioning/merging.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::cmp; - -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder}; -use rustc_span::symbol::Symbol; - -use super::PartitioningCx; -use crate::partitioning::PreInliningPartitioning; - -pub fn merge_codegen_units<'tcx>( - cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, -) { - assert!(cx.target_cgu_count >= 1); - let codegen_units = &mut initial_partitioning.codegen_units; - - // Note that at this point in time the `codegen_units` here may not be in a - // deterministic order (but we know they're deterministically the same set). - // We want this merging to produce a deterministic ordering of codegen units - // from the input. - // - // Due to basically how we've implemented the merging below (merge the two - // smallest into each other) we're sure to start off with a deterministic - // order (sorted by name). This'll mean that if two cgus have the same size - // the stable sort below will keep everything nice and deterministic. - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - - // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = - codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); - - // Merge the two smallest codegen units until the target size is reached. - while codegen_units.len() > cx.target_cgu_count { - // Sort small cgus to the back - codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); - let mut smallest = codegen_units.pop().unwrap(); - let second_smallest = codegen_units.last_mut().unwrap(); - - // Move the mono-items from `smallest` to `second_smallest` - second_smallest.modify_size_estimate(smallest.size_estimate()); - for (k, v) in smallest.items_mut().drain() { - second_smallest.items_mut().insert(k, v); - } - - // Record that `second_smallest` now contains all the stuff that was in - // `smallest` before. - let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap(); - cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names); - - debug!( - "CodegenUnit {} merged into CodegenUnit {}", - smallest.name(), - second_smallest.name() - ); - } - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - - if cx.tcx.sess.opts.incremental.is_some() { - // If we are doing incremental compilation, we want CGU names to - // reflect the path of the source level module they correspond to. - // For CGUs that contain the code of multiple modules because of the - // merging done above, we use a concatenation of the names of - // all contained CGUs. - let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. - - // We are sorting primitive &strs here so we can use unstable sort - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); - - for cgu in codegen_units.iter_mut() { - if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names { - cgu.set_name(Symbol::intern(&new_cgu_name)); - } else { - // If we don't require CGU names to be human-readable, we - // use a fixed length hash of the composite CGU name - // instead. - let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name); - cgu.set_name(Symbol::intern(&new_cgu_name)); - } - } - } - } else { - // If we are compiling non-incrementally we just generate simple CGU - // names containing an index. - for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index)); - } - } -} - -fn numbered_codegen_unit_name( - name_builder: &mut CodegenUnitNameBuilder<'_>, - index: usize, -) -> Symbol { - name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index)) -} diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 18aa0742c..d0b23ca9e 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -93,7 +93,6 @@ //! inlining, even when they are not marked `#[inline]`. mod default; -mod merging; use std::cmp; use std::fs::{self, File}; @@ -106,8 +105,8 @@ use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE}; use rustc_middle::mir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_span::symbol::Symbol; @@ -118,58 +117,135 @@ use crate::errors::{ CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy, }; -pub struct PartitioningCx<'a, 'tcx> { +enum Partitioner { + Default(default::DefaultPartitioning), + // Other partitioning strategies can go here. + Unknown, +} + +impl<'tcx> Partition<'tcx> for Partitioner { + fn place_root_mono_items<I>( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + mono_items: &mut I, + ) -> PlacedRootMonoItems<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>, + { + match self { + Partitioner::Default(partitioner) => partitioner.place_root_mono_items(cx, mono_items), + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn merge_codegen_units( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut Vec<CodegenUnit<'tcx>>, + ) { + match self { + Partitioner::Default(partitioner) => partitioner.merge_codegen_units(cx, codegen_units), + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn place_inlined_mono_items( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet<MonoItem<'tcx>>, + ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> { + match self { + Partitioner::Default(partitioner) => { + partitioner.place_inlined_mono_items(cx, codegen_units, roots) + } + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } + + fn internalize_symbols( + &mut self, + cx: &PartitioningCx<'_, 'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, + ) { + match self { + Partitioner::Default(partitioner) => partitioner.internalize_symbols( + cx, + codegen_units, + mono_item_placements, + internalization_candidates, + ), + Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy), + } + } +} + +struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, target_cgu_count: usize, inlining_map: &'a InliningMap<'tcx>, } -trait Partitioner<'tcx> { - fn place_root_mono_items( +pub struct PlacedRootMonoItems<'tcx> { + codegen_units: Vec<CodegenUnit<'tcx>>, + roots: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, +} + +trait Partition<'tcx> { + fn place_root_mono_items<I>( &mut self, cx: &PartitioningCx<'_, 'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, - ) -> PreInliningPartitioning<'tcx>; + mono_items: &mut I, + ) -> PlacedRootMonoItems<'tcx> + where + I: Iterator<Item = MonoItem<'tcx>>; fn merge_codegen_units( &mut self, cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: &mut PreInliningPartitioning<'tcx>, + codegen_units: &mut Vec<CodegenUnit<'tcx>>, ); fn place_inlined_mono_items( &mut self, cx: &PartitioningCx<'_, 'tcx>, - initial_partitioning: PreInliningPartitioning<'tcx>, - ) -> PostInliningPartitioning<'tcx>; + codegen_units: &mut [CodegenUnit<'tcx>], + roots: FxHashSet<MonoItem<'tcx>>, + ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement>; fn internalize_symbols( &mut self, cx: &PartitioningCx<'_, 'tcx>, - partitioning: &mut PostInliningPartitioning<'tcx>, + codegen_units: &mut [CodegenUnit<'tcx>], + mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, + internalization_candidates: FxHashSet<MonoItem<'tcx>>, ); } -fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> { +fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner { let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy { None => "default", Some(s) => &s[..], }; match strategy { - "default" => Box::new(default::DefaultPartitioning), - _ => { - tcx.sess.emit_fatal(UnknownPartitionStrategy); - } + "default" => Partitioner::Default(default::DefaultPartitioning), + _ => Partitioner::Unknown, } } -pub fn partition<'tcx>( +fn partition<'tcx, I>( tcx: TyCtxt<'tcx>, - mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>, + mono_items: &mut I, max_cgu_count: usize, inlining_map: &InliningMap<'tcx>, -) -> Vec<CodegenUnit<'tcx>> { +) -> Vec<CodegenUnit<'tcx>> +where + I: Iterator<Item = MonoItem<'tcx>>, +{ let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let mut partitioner = get_partitioner(tcx); @@ -177,40 +253,51 @@ pub fn partition<'tcx>( // In the first step, we place all regular monomorphizations into their // respective 'home' codegen unit. Regular monomorphizations are all // functions and statics defined in the local crate. - let mut initial_partitioning = { + let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); partitioner.place_root_mono_items(cx, mono_items) }; - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); + for cgu in &mut codegen_units { + cgu.create_size_estimate(tcx); + } - debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITIONING", &codegen_units); // Merge until we have at most `max_cgu_count` codegen units. + // `merge_codegen_units` is responsible for updating the CGU size + // estimates. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); - partitioner.merge_codegen_units(cx, &mut initial_partitioning); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + partitioner.merge_codegen_units(cx, &mut codegen_units); + debug_dump(tcx, "POST MERGING", &codegen_units); } // In the next step, we use the inlining map to determine which additional // monomorphizations have to go into each codegen unit. These additional // monomorphizations can be drop-glue, functions from external crates, and // local functions the definition of which is marked with `#[inline]`. - let mut post_inlining = { + let mono_item_placements = { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); - partitioner.place_inlined_mono_items(cx, initial_partitioning) + partitioner.place_inlined_mono_items(cx, &mut codegen_units, roots) }; - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); + for cgu in &mut codegen_units { + cgu.create_size_estimate(tcx); + } - debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); + debug_dump(tcx, "POST INLINING", &codegen_units); // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(cx, &mut post_inlining); + partitioner.internalize_symbols( + cx, + &mut codegen_units, + mono_item_placements, + internalization_candidates, + ); } let instrument_dead_code = @@ -218,7 +305,7 @@ pub fn partition<'tcx>( if instrument_dead_code { assert!( - post_inlining.codegen_units.len() > 0, + codegen_units.len() > 0, "There must be at least one CGU that code coverage data can be generated in." ); @@ -229,7 +316,7 @@ pub fn partition<'tcx>( // the object file (CGU) containing the dead function stubs is included // in the final binary. This will probably require forcing these // function symbols to be included via `-u` or `/include` linker args. - let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect(); + let mut cgus: Vec<_> = codegen_units.iter_mut().collect(); cgus.sort_by_key(|cgu| cgu.size_estimate()); let dead_code_cgu = @@ -240,27 +327,17 @@ pub fn partition<'tcx>( } else { // If there are no CGUs that have externally linked items, // then we just pick the first CGU as a fallback. - &mut post_inlining.codegen_units[0] + &mut codegen_units[0] }; dead_code_cgu.make_code_coverage_dead_code_cgu(); } // Finally, sort by codegen unit name, so that we get deterministic results. - let PostInliningPartitioning { - codegen_units: mut result, - mono_item_placements: _, - internalization_candidates: _, - } = post_inlining; + codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); - result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + debug_dump(tcx, "FINAL", &codegen_units); - result -} - -pub struct PreInliningPartitioning<'tcx> { - codegen_units: Vec<CodegenUnit<'tcx>>, - roots: FxHashSet<MonoItem<'tcx>>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, + codegen_units } /// For symbol internalization, we need to know whether a symbol/mono-item is @@ -272,39 +349,37 @@ enum MonoItemPlacement { MultipleCgus, } -struct PostInliningPartitioning<'tcx> { - codegen_units: Vec<CodegenUnit<'tcx>>, - mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, -} - -fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) -where - I: Iterator<Item = &'a CodegenUnit<'tcx>>, - 'tcx: 'a, -{ +fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; + let num_cgus = cgus.len(); + let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); + let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); + let ratio = max as f64 / min as f64; + let s = &mut String::new(); - let _ = writeln!(s, "{label}"); + let _ = writeln!( + s, + "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" + ); for cgu in cgus { let _ = - writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); + writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); for (mono_item, linkage) in cgu.items() { let symbol_name = mono_item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]); - let _ = writeln!( + let _ = with_no_trimmed_paths!(writeln!( s, " - {} [{:?}] [{}] estimated size {}", mono_item, linkage, symbol_hash, mono_item.size_estimate(tcx) - ); + )); } let _ = writeln!(s); @@ -380,7 +455,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co || { let mut codegen_units = partition( tcx, - &mut items.iter().cloned(), + &mut items.iter().copied(), tcx.sess.codegen_units(), &inlining_map, ); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 63263a642..88a3e0285 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -11,9 +11,9 @@ use rustc_middle::mir::{ visit::{TyContext, Visitor}, Constant, ConstantKind, Local, LocalDecl, Location, }; +use rustc_middle::query::Providers; use rustc_middle::ty::{ self, - query::Providers, subst::SubstsRef, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}, Const, Ty, TyCtxt, UnusedGenericParams, @@ -232,7 +232,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, generator or constant). #[instrument(level = "debug", skip(self, def_id, substs))] fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) { - let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)); + let instance = ty::InstanceDef::Item(def_id); let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in substs.iter().enumerate() { @@ -272,10 +272,10 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { // Avoid considering `T` unused when constants are of the form: // `<Self as Foo<T>>::foo::promoted[p]` if let Some(p) = promoted { - if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self { + if self.def_id == def && !self.tcx.generics_of(def).has_self { // If there is a promoted, don't look at the substs - since it will always contain // the generic parameters, instead, traverse the promoted MIR. - let promoted = self.tcx.promoted_mir(def.did); + let promoted = self.tcx.promoted_mir(def); self.visit_body(&promoted[p]); } } @@ -305,9 +305,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> { ControlFlow::Continue(()) } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) - if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => + if matches!(self.tcx.def_kind(def), DefKind::AnonConst) => { - self.visit_child_body(def.did, substs); + self.visit_child_body(def, substs); ControlFlow::Continue(()) } _ => c.super_visit_with(self), diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 33e1f6ce3..d12bfc6f6 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let before_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - before_feature_tys, + ty::EarlyBinder(before_feature_tys), ); let after_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - after_feature_tys, + ty::EarlyBinder(after_feature_tys), ); let new_size = tcx |