Remove -Zcgu-partitioning-strategy.

This option was introduced three years ago, but it's never been
meaningfully used, and `default` is the only acceptable value.

Also, I think the `Partition` trait presents an interface that is too
closely tied to the existing strategy and would probably be wrong for
other strategies. (My rule of thumb is to not make something generic
until there are at least two instances of it, to avoid this kind of
problem.)

Also, I don't think providing multiple partitioning strategies to the
user is a good idea, because the compiler already has enough obscure
knobs.

This commit removes the option, along with the `Partition` trait, and
the `Partitioner` and `DefaultPartitioning` types. I left the existing
code in `compiler/rustc_monomorphize/src/partitioning/default.rs`,
though I could be persuaded that moving it into
`compiler/rustc_monomorphize/src/partitioning/mod.rs` is better.
This commit is contained in:
Nicholas Nethercote 2023-05-29 09:56:37 +10:00
parent 1c53407e8c
commit 97d4a38de9
3 changed files with 279 additions and 399 deletions

View File

@ -15,326 +15,319 @@ use rustc_span::symbol::Symbol;
use super::PartitioningCx; use super::PartitioningCx;
use crate::collector::InliningMap; use crate::collector::InliningMap;
use crate::partitioning::{MonoItemPlacement, Partition, PlacedRootMonoItems}; use crate::partitioning::{MonoItemPlacement, PlacedRootMonoItems};
pub struct DefaultPartitioning; // This modules implements the default (and only) partitioning strategy.
impl<'tcx> Partition<'tcx> for DefaultPartitioning { pub(super) fn place_root_mono_items<'tcx, I>(
fn place_root_mono_items<I>( cx: &PartitioningCx<'_, 'tcx>,
&mut self, mono_items: &mut I,
cx: &PartitioningCx<'_, 'tcx>, ) -> PlacedRootMonoItems<'tcx>
mono_items: &mut I, where
) -> PlacedRootMonoItems<'tcx> I: Iterator<Item = MonoItem<'tcx>>,
where {
I: Iterator<Item = MonoItem<'tcx>>, let mut roots = FxHashSet::default();
{ let mut codegen_units = FxHashMap::default();
let mut roots = FxHashSet::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
let mut codegen_units = FxHashMap::default(); let mut internalization_candidates = FxHashSet::default();
let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
let mut internalization_candidates = FxHashSet::default();
// Determine if monomorphizations instantiated in this crate will be made // Determine if monomorphizations instantiated in this crate will be made
// available to downstream crates. This depends on whether we are in // available to downstream crates. This depends on whether we are in
// share-generics mode and whether the current crate can even have // share-generics mode and whether the current crate can even have
// downstream crates. // downstream crates.
let export_generics = let export_generics =
cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
let cgu_name_cache = &mut FxHashMap::default(); let cgu_name_cache = &mut FxHashMap::default();
for mono_item in mono_items { for mono_item in mono_items {
match mono_item.instantiation_mode(cx.tcx) { match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {} InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => continue, InstantiationMode::LocalCopy => continue,
} }
let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
let is_volatile = is_incremental_build && mono_item.is_generic_fn(); let is_volatile = is_incremental_build && mono_item.is_generic_fn();
let codegen_unit_name = match characteristic_def_id { let codegen_unit_name = match characteristic_def_id {
Some(def_id) => compute_codegen_unit_name( Some(def_id) => compute_codegen_unit_name(
cx.tcx,
cgu_name_builder,
def_id,
is_volatile,
cgu_name_cache,
),
None => fallback_cgu_name(cgu_name_builder),
};
let codegen_unit = codegen_units
.entry(codegen_unit_name)
.or_insert_with(|| CodegenUnit::new(codegen_unit_name));
let mut can_be_internalized = true;
let (linkage, visibility) = mono_item_linkage_and_visibility(
cx.tcx, cx.tcx,
&mono_item, cgu_name_builder,
&mut can_be_internalized, def_id,
export_generics, is_volatile,
); cgu_name_cache,
if visibility == Visibility::Hidden && can_be_internalized { ),
internalization_candidates.insert(mono_item); None => fallback_cgu_name(cgu_name_builder),
} };
codegen_unit.items_mut().insert(mono_item, (linkage, visibility)); let codegen_unit = codegen_units
roots.insert(mono_item); .entry(codegen_unit_name)
.or_insert_with(|| CodegenUnit::new(codegen_unit_name));
let mut can_be_internalized = true;
let (linkage, visibility) = mono_item_linkage_and_visibility(
cx.tcx,
&mono_item,
&mut can_be_internalized,
export_generics,
);
if visibility == Visibility::Hidden && can_be_internalized {
internalization_candidates.insert(mono_item);
} }
// Always ensure we have at least one CGU; otherwise, if we have a codegen_unit.items_mut().insert(mono_item, (linkage, visibility));
// crate with just types (for example), we could wind up with no CGU. roots.insert(mono_item);
if codegen_units.is_empty() {
let codegen_unit_name = fallback_cgu_name(cgu_name_builder);
codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name));
}
let codegen_units = codegen_units.into_values().collect();
PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
} }
fn merge_codegen_units( // Always ensure we have at least one CGU; otherwise, if we have a
&mut self, // crate with just types (for example), we could wind up with no CGU.
cx: &PartitioningCx<'_, 'tcx>, if codegen_units.is_empty() {
codegen_units: &mut Vec<CodegenUnit<'tcx>>, let codegen_unit_name = fallback_cgu_name(cgu_name_builder);
) { codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name));
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( let codegen_units = codegen_units.into_values().collect();
&mut self, PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
cx: &PartitioningCx<'_, 'tcx>, }
codegen_units: &mut [CodegenUnit<'tcx>],
roots: FxHashSet<MonoItem<'tcx>>,
) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
let mut mono_item_placements = FxHashMap::default();
let single_codegen_unit = codegen_units.len() == 1; pub(super) fn merge_codegen_units<'tcx>(
cx: &PartitioningCx<'_, 'tcx>,
codegen_units: &mut Vec<CodegenUnit<'tcx>>,
) {
assert!(cx.target_cgu_count >= 1);
for old_codegen_unit in codegen_units.iter_mut() { // Note that at this point in time the `codegen_units` here may not be
// Collect all items that need to be available in this codegen unit. // in a deterministic order (but we know they're deterministically the
let mut reachable = FxHashSet::default(); // same set). We want this merging to produce a deterministic ordering
for root in old_codegen_unit.items().keys() { // of codegen units from the input.
follow_inlining(*root, cx.inlining_map, &mut reachable); //
} // 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()));
let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); // 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();
// Add all monomorphizations that are not already there. // Merge the two smallest codegen units until the target size is
for mono_item in reachable { // reached.
if let Some(linkage) = old_codegen_unit.items().get(&mono_item) { while codegen_units.len() > cx.target_cgu_count {
// This is a root, just copy it over. // Sort small cgus to the back
new_codegen_unit.items_mut().insert(mono_item, *linkage); 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 { } else {
if roots.contains(&mono_item) { // If we don't require CGU names to be human-readable,
bug!( // we use a fixed length hash of the composite CGU name
"GloballyShared mono-item inlined into other CGU: \ // instead.
{:?}", let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
mono_item cgu.set_name(Symbol::intern(&new_cgu_name));
);
}
// This is a CGU-private copy.
new_codegen_unit
.items_mut()
.insert(mono_item, (Linkage::Internal, Visibility::Default));
}
if !single_codegen_unit {
// If there is more than one codegen unit, we need to keep track
// in which codegen units each monomorphization is placed.
match mono_item_placements.entry(mono_item) {
Entry::Occupied(e) => {
let placement = e.into_mut();
debug_assert!(match *placement {
MonoItemPlacement::SingleCgu { cgu_name } => {
cgu_name != new_codegen_unit.name()
}
MonoItemPlacement::MultipleCgus => true,
});
*placement = MonoItemPlacement::MultipleCgus;
}
Entry::Vacant(e) => {
e.insert(MonoItemPlacement::SingleCgu {
cgu_name: new_codegen_unit.name(),
});
}
}
} }
} }
*old_codegen_unit = new_codegen_unit;
} }
} else {
return mono_item_placements; // If we are compiling non-incrementally we just generate simple CGU
// names containing an index.
fn follow_inlining<'tcx>( for (index, cgu) in codegen_units.iter_mut().enumerate() {
mono_item: MonoItem<'tcx>, let numbered_codegen_unit_name =
inlining_map: &InliningMap<'tcx>, cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index));
visited: &mut FxHashSet<MonoItem<'tcx>>, cgu.set_name(numbered_codegen_unit_name);
) {
if !visited.insert(mono_item) {
return;
}
inlining_map.with_inlining_candidates(mono_item, |target| {
follow_inlining(target, inlining_map, visited);
});
} }
} }
}
fn internalize_symbols( pub(super) fn place_inlined_mono_items<'tcx>(
&mut self, cx: &PartitioningCx<'_, 'tcx>,
cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut [CodegenUnit<'tcx>],
codegen_units: &mut [CodegenUnit<'tcx>], roots: FxHashSet<MonoItem<'tcx>>,
mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>, ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
internalization_candidates: FxHashSet<MonoItem<'tcx>>, let mut mono_item_placements = FxHashMap::default();
) {
if codegen_units.len() == 1 { let single_codegen_unit = 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 for old_codegen_unit in codegen_units.iter_mut() {
// could be accessed from. // Collect all items that need to be available in this codegen unit.
for cgu in codegen_units { let mut reachable = FxHashSet::default();
for candidate in &internalization_candidates { for root in old_codegen_unit.items().keys() {
cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default)); follow_inlining(*root, cx.inlining_map, &mut reachable);
}
let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name());
// Add all monomorphizations that are not already there.
for mono_item in reachable {
if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
// This is a root, just copy it over.
new_codegen_unit.items_mut().insert(mono_item, *linkage);
} else {
if roots.contains(&mono_item) {
bug!(
"GloballyShared mono-item inlined into other CGU: \
{:?}",
mono_item
);
} }
// This is a CGU-private copy.
new_codegen_unit
.items_mut()
.insert(mono_item, (Linkage::Internal, Visibility::Default));
} }
if !single_codegen_unit {
// If there is more than one codegen unit, we need to keep track
// in which codegen units each monomorphization is placed.
match mono_item_placements.entry(mono_item) {
Entry::Occupied(e) => {
let placement = e.into_mut();
debug_assert!(match *placement {
MonoItemPlacement::SingleCgu { cgu_name } => {
cgu_name != new_codegen_unit.name()
}
MonoItemPlacement::MultipleCgus => true,
});
*placement = MonoItemPlacement::MultipleCgus;
}
Entry::Vacant(e) => {
e.insert(MonoItemPlacement::SingleCgu {
cgu_name: new_codegen_unit.name(),
});
}
}
}
}
*old_codegen_unit = new_codegen_unit;
}
return mono_item_placements;
fn follow_inlining<'tcx>(
mono_item: MonoItem<'tcx>,
inlining_map: &InliningMap<'tcx>,
visited: &mut FxHashSet<MonoItem<'tcx>>,
) {
if !visited.insert(mono_item) {
return; return;
} }
// Build a map from every monomorphization to all the monomorphizations that inlining_map.with_inlining_candidates(mono_item, |target| {
// reference it. follow_inlining(target, inlining_map, visited);
let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default();
cx.inlining_map.iter_accesses(|accessor, accessees| {
for accessee in accessees {
accessor_map.entry(*accessee).or_default().push(accessor);
}
}); });
}
}
// For each internalization candidates in each codegen unit, check if it is pub(super) fn internalize_symbols<'tcx>(
// accessed from outside its defining codegen unit. cx: &PartitioningCx<'_, 'tcx>,
codegen_units: &mut [CodegenUnit<'tcx>],
mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
internalization_candidates: FxHashSet<MonoItem<'tcx>>,
) {
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 codegen_units { for cgu in codegen_units {
let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() }; for candidate in &internalization_candidates {
cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default));
}
}
for (accessee, linkage_and_visibility) in cgu.items_mut() { return;
if !internalization_candidates.contains(accessee) { }
// This item is no candidate for internalizing, so skip it.
// Build a map from every monomorphization to all the monomorphizations that
// reference it.
let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default();
cx.inlining_map.iter_accesses(|accessor, accessees| {
for accessee in accessees {
accessor_map.entry(*accessee).or_default().push(accessor);
}
});
// For each internalization candidates in each codegen unit, check if it is
// accessed from outside its defining codegen unit.
for cgu in codegen_units {
let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() };
for (accessee, linkage_and_visibility) in cgu.items_mut() {
if !internalization_candidates.contains(accessee) {
// This item is no candidate for internalizing, so skip it.
continue;
}
debug_assert_eq!(mono_item_placements[accessee], home_cgu);
if let Some(accessors) = accessor_map.get(accessee) {
if accessors
.iter()
.filter_map(|accessor| {
// Some accessors might not have been
// instantiated. We can safely ignore those.
mono_item_placements.get(accessor)
})
.any(|placement| *placement != home_cgu)
{
// Found an accessor from another CGU, so skip to the next
// item without marking this one as internal.
continue; continue;
} }
debug_assert_eq!(mono_item_placements[accessee], home_cgu);
if let Some(accessors) = accessor_map.get(accessee) {
if accessors
.iter()
.filter_map(|accessor| {
// Some accessors might not have been
// instantiated. We can safely ignore those.
mono_item_placements.get(accessor)
})
.any(|placement| *placement != home_cgu)
{
// Found an accessor from another CGU, so skip to the next
// item without marking this one as internal.
continue;
}
}
// If we got here, we did not find any accesses from other CGUs,
// so it's fine to make this monomorphization internal.
*linkage_and_visibility = (Linkage::Internal, Visibility::Default);
} }
// If we got here, we did not find any accesses from other CGUs,
// so it's fine to make this monomorphization internal.
*linkage_and_visibility = (Linkage::Internal, Visibility::Default);
} }
} }
} }

View File

@ -113,74 +113,7 @@ use rustc_span::symbol::Symbol;
use crate::collector::InliningMap; use crate::collector::InliningMap;
use crate::collector::{self, MonoItemCollectionMode}; use crate::collector::{self, MonoItemCollectionMode};
use crate::errors::{ use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode};
CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy,
};
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> { struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
@ -194,49 +127,6 @@ pub struct PlacedRootMonoItems<'tcx> {
internalization_candidates: 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 I,
) -> PlacedRootMonoItems<'tcx>
where
I: Iterator<Item = MonoItem<'tcx>>;
fn merge_codegen_units(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
codegen_units: &mut Vec<CodegenUnit<'tcx>>,
);
fn place_inlined_mono_items(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
codegen_units: &mut [CodegenUnit<'tcx>],
roots: FxHashSet<MonoItem<'tcx>>,
) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement>;
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>>,
);
}
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" => Partitioner::Default(default::DefaultPartitioning),
_ => Partitioner::Unknown,
}
}
fn partition<'tcx, I>( fn partition<'tcx, I>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
mono_items: &mut I, mono_items: &mut I,
@ -248,14 +138,13 @@ where
{ {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning"); let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
let mut partitioner = get_partitioner(tcx);
let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map }; let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map };
// In the first step, we place all regular monomorphizations into their // In the first step, we place all regular monomorphizations into their
// respective 'home' codegen unit. Regular monomorphizations are all // respective 'home' codegen unit. Regular monomorphizations are all
// functions and statics defined in the local crate. // functions and statics defined in the local crate.
let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = { let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots"); let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
partitioner.place_root_mono_items(cx, mono_items) default::place_root_mono_items(cx, mono_items)
}; };
for cgu in &mut codegen_units { for cgu in &mut codegen_units {
@ -269,7 +158,7 @@ where
// estimates. // estimates.
{ {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
partitioner.merge_codegen_units(cx, &mut codegen_units); default::merge_codegen_units(cx, &mut codegen_units);
debug_dump(tcx, "POST MERGING", &codegen_units); debug_dump(tcx, "POST MERGING", &codegen_units);
} }
@ -279,7 +168,7 @@ where
// local functions the definition of which is marked with `#[inline]`. // local functions the definition of which is marked with `#[inline]`.
let mono_item_placements = { let mono_item_placements = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items"); let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
partitioner.place_inlined_mono_items(cx, &mut codegen_units, roots) default::place_inlined_mono_items(cx, &mut codegen_units, roots)
}; };
for cgu in &mut codegen_units { for cgu in &mut codegen_units {
@ -292,7 +181,7 @@ where
// more freedom to optimize. // more freedom to optimize.
if !tcx.sess.link_dead_code() { if !tcx.sess.link_dead_code() {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
partitioner.internalize_symbols( default::internalize_symbols(
cx, cx,
&mut codegen_units, &mut codegen_units,
mono_item_placements, mono_item_placements,

View File

@ -1372,8 +1372,6 @@ options! {
"set options for branch target identification and pointer authentication on AArch64"), "set options for branch target identification and pointer authentication on AArch64"),
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
"instrument control-flow architecture protection"), "instrument control-flow architecture protection"),
cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
"the codegen unit partitioning strategy to use"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED], codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"), "the backend to use"),
combine_cgu: bool = (false, parse_bool, [TRACKED], combine_cgu: bool = (false, parse_bool, [TRACKED],