Add a CGU partitioning trait
This will allow us to prototype different partitioning schemes without adding a lot of extra conditionals everywhere.
This commit is contained in:
parent
d9d4d39612
commit
8dea3088c6
1 changed files with 350 additions and 303 deletions
|
@ -111,28 +111,60 @@ use rustc_span::symbol::{Symbol, SymbolStr};
|
|||
use crate::monomorphize::collector::InliningMap;
|
||||
use crate::monomorphize::collector::{self, MonoItemCollectionMode};
|
||||
|
||||
trait Partitioner<'tcx> {
|
||||
fn place_root_mono_items(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
|
||||
) -> PreInliningPartitioning<'tcx>;
|
||||
|
||||
fn merge_codegen_units(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
|
||||
target_cgu_count: usize,
|
||||
);
|
||||
|
||||
fn place_inlined_mono_items(
|
||||
&mut self,
|
||||
initial_partitioning: PreInliningPartitioning<'tcx>,
|
||||
inlining_map: &InliningMap<'tcx>,
|
||||
) -> PostInliningPartitioning<'tcx>;
|
||||
|
||||
fn internalize_symbols(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
partitioning: &mut PostInliningPartitioning<'tcx>,
|
||||
inlining_map: &InliningMap<'tcx>,
|
||||
);
|
||||
}
|
||||
|
||||
// Anything we can't find a proper codegen unit for goes into this.
|
||||
fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_>) -> Symbol {
|
||||
name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu"))
|
||||
}
|
||||
|
||||
pub fn partition<'tcx, I>(
|
||||
pub struct DefaultPartitioning;
|
||||
|
||||
fn get_partitioner<'tcx>() -> Box<dyn Partitioner<'tcx>> {
|
||||
Box::new(DefaultPartitioning)
|
||||
}
|
||||
|
||||
pub fn partition<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_items: I,
|
||||
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
|
||||
max_cgu_count: usize,
|
||||
inlining_map: &InliningMap<'tcx>,
|
||||
) -> Vec<CodegenUnit<'tcx>>
|
||||
where
|
||||
I: Iterator<Item = MonoItem<'tcx>>,
|
||||
{
|
||||
) -> Vec<CodegenUnit<'tcx>> {
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
|
||||
|
||||
let mut partitioner = get_partitioner();
|
||||
// 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 _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
|
||||
place_root_mono_items(tcx, mono_items)
|
||||
partitioner.place_root_mono_items(tcx, mono_items)
|
||||
};
|
||||
|
||||
initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
|
||||
|
@ -142,7 +174,7 @@ where
|
|||
// Merge until we have at most `max_cgu_count` codegen units.
|
||||
{
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
|
||||
merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count);
|
||||
partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count);
|
||||
debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
|
||||
}
|
||||
|
||||
|
@ -152,7 +184,7 @@ where
|
|||
// local functions the definition of which is marked with `#[inline]`.
|
||||
let mut post_inlining = {
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
|
||||
place_inlined_mono_items(initial_partitioning, inlining_map)
|
||||
partitioner.place_inlined_mono_items(initial_partitioning, inlining_map)
|
||||
};
|
||||
|
||||
post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
|
||||
|
@ -163,7 +195,7 @@ where
|
|||
// more freedom to optimize.
|
||||
if tcx.sess.opts.cg.link_dead_code != Some(true) {
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
|
||||
internalize_symbols(tcx, &mut post_inlining, inlining_map);
|
||||
partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map);
|
||||
}
|
||||
|
||||
// Finally, sort by codegen unit name, so that we get deterministic results.
|
||||
|
@ -199,77 +231,6 @@ struct PostInliningPartitioning<'tcx> {
|
|||
internalization_candidates: FxHashSet<MonoItem<'tcx>>,
|
||||
}
|
||||
|
||||
fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx>
|
||||
where
|
||||
I: Iterator<Item = MonoItem<'tcx>>,
|
||||
{
|
||||
let mut roots = FxHashSet::default();
|
||||
let mut codegen_units = FxHashMap::default();
|
||||
let is_incremental_build = tcx.sess.opts.incremental.is_some();
|
||||
let mut internalization_candidates = FxHashSet::default();
|
||||
|
||||
// Determine if monomorphizations instantiated in this crate will be made
|
||||
// available to downstream crates. This depends on whether we are in
|
||||
// share-generics mode and whether the current crate can even have
|
||||
// downstream crates.
|
||||
let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics();
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let cgu_name_cache = &mut FxHashMap::default();
|
||||
|
||||
for mono_item in mono_items {
|
||||
match mono_item.instantiation_mode(tcx) {
|
||||
InstantiationMode::GloballyShared { .. } => {}
|
||||
InstantiationMode::LocalCopy => continue,
|
||||
}
|
||||
|
||||
let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item);
|
||||
let is_volatile = is_incremental_build && mono_item.is_generic_fn();
|
||||
|
||||
let codegen_unit_name = match characteristic_def_id {
|
||||
Some(def_id) => compute_codegen_unit_name(
|
||||
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(
|
||||
tcx,
|
||||
&mono_item,
|
||||
&mut can_be_internalized,
|
||||
export_generics,
|
||||
);
|
||||
if visibility == Visibility::Hidden && can_be_internalized {
|
||||
internalization_candidates.insert(mono_item);
|
||||
}
|
||||
|
||||
codegen_unit.items_mut().insert(mono_item, (linkage, visibility));
|
||||
roots.insert(mono_item);
|
||||
}
|
||||
|
||||
// Always ensure we have at least one CGU; otherwise, if we have a
|
||||
// crate with just types (for example), we could wind up with no CGU.
|
||||
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));
|
||||
}
|
||||
|
||||
PreInliningPartitioning {
|
||||
codegen_units: codegen_units.into_iter().map(|(_, codegen_unit)| codegen_unit).collect(),
|
||||
roots,
|
||||
internalization_candidates,
|
||||
}
|
||||
}
|
||||
|
||||
fn mono_item_linkage_and_visibility(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_item: &MonoItem<'tcx>,
|
||||
|
@ -452,11 +413,88 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
|
|||
}
|
||||
}
|
||||
|
||||
fn merge_codegen_units<'tcx>(
|
||||
impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
|
||||
fn place_root_mono_items(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
|
||||
) -> PreInliningPartitioning<'tcx> {
|
||||
let mut roots = FxHashSet::default();
|
||||
let mut codegen_units = FxHashMap::default();
|
||||
let is_incremental_build = tcx.sess.opts.incremental.is_some();
|
||||
let mut internalization_candidates = FxHashSet::default();
|
||||
|
||||
// Determine if monomorphizations instantiated in this crate will be made
|
||||
// available to downstream crates. This depends on whether we are in
|
||||
// share-generics mode and whether the current crate can even have
|
||||
// downstream crates.
|
||||
let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics();
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let cgu_name_cache = &mut FxHashMap::default();
|
||||
|
||||
for mono_item in mono_items {
|
||||
match mono_item.instantiation_mode(tcx) {
|
||||
InstantiationMode::GloballyShared { .. } => {}
|
||||
InstantiationMode::LocalCopy => continue,
|
||||
}
|
||||
|
||||
let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item);
|
||||
let is_volatile = is_incremental_build && mono_item.is_generic_fn();
|
||||
|
||||
let codegen_unit_name = match characteristic_def_id {
|
||||
Some(def_id) => compute_codegen_unit_name(
|
||||
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(
|
||||
tcx,
|
||||
&mono_item,
|
||||
&mut can_be_internalized,
|
||||
export_generics,
|
||||
);
|
||||
if visibility == Visibility::Hidden && can_be_internalized {
|
||||
internalization_candidates.insert(mono_item);
|
||||
}
|
||||
|
||||
codegen_unit.items_mut().insert(mono_item, (linkage, visibility));
|
||||
roots.insert(mono_item);
|
||||
}
|
||||
|
||||
// Always ensure we have at least one CGU; otherwise, if we have a
|
||||
// crate with just types (for example), we could wind up with no CGU.
|
||||
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));
|
||||
}
|
||||
|
||||
PreInliningPartitioning {
|
||||
codegen_units: codegen_units
|
||||
.into_iter()
|
||||
.map(|(_, codegen_unit)| codegen_unit)
|
||||
.collect(),
|
||||
roots,
|
||||
internalization_candidates,
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_codegen_units(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
|
||||
target_cgu_count: usize,
|
||||
) {
|
||||
) {
|
||||
assert!(target_cgu_count >= 1);
|
||||
let codegen_units = &mut initial_partitioning.codegen_units;
|
||||
|
||||
|
@ -491,7 +529,10 @@ fn merge_codegen_units<'tcx>(
|
|||
// 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().extend(consumed_cgu_names.drain(..));
|
||||
cgu_contents
|
||||
.get_mut(&second_smallest.name())
|
||||
.unwrap()
|
||||
.extend(consumed_cgu_names.drain(..));
|
||||
|
||||
debug!(
|
||||
"CodegenUnit {} merged into CodegenUnit {}",
|
||||
|
@ -544,17 +585,21 @@ fn merge_codegen_units<'tcx>(
|
|||
cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn place_inlined_mono_items<'tcx>(
|
||||
fn place_inlined_mono_items(
|
||||
&mut self,
|
||||
initial_partitioning: PreInliningPartitioning<'tcx>,
|
||||
inlining_map: &InliningMap<'tcx>,
|
||||
) -> PostInliningPartitioning<'tcx> {
|
||||
) -> PostInliningPartitioning<'tcx> {
|
||||
let mut new_partitioning = Vec::new();
|
||||
let mut mono_item_placements = FxHashMap::default();
|
||||
|
||||
let PreInliningPartitioning { codegen_units: initial_cgus, roots, internalization_candidates } =
|
||||
initial_partitioning;
|
||||
let PreInliningPartitioning {
|
||||
codegen_units: initial_cgus,
|
||||
roots,
|
||||
internalization_candidates,
|
||||
} = initial_partitioning;
|
||||
|
||||
let single_codegen_unit = initial_cgus.len() == 1;
|
||||
|
||||
|
@ -632,13 +677,14 @@ fn place_inlined_mono_items<'tcx>(
|
|||
follow_inlining(target, inlining_map, visited);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn internalize_symbols<'tcx>(
|
||||
fn internalize_symbols(
|
||||
&mut self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
partitioning: &mut PostInliningPartitioning<'tcx>,
|
||||
inlining_map: &InliningMap<'tcx>,
|
||||
) {
|
||||
) {
|
||||
if partitioning.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
|
||||
|
@ -696,6 +742,7 @@ fn internalize_symbols<'tcx>(
|
|||
*linkage_and_visibility = (Linkage::Internal, Visibility::Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn characteristic_def_id_of_mono_item<'tcx>(
|
||||
|
@ -923,7 +970,7 @@ fn collect_and_partition_mono_items(
|
|||
|| {
|
||||
&*tcx.arena.alloc_from_iter(partition(
|
||||
tcx,
|
||||
items.iter().cloned(),
|
||||
&mut items.iter().cloned(),
|
||||
tcx.sess.codegen_units(),
|
||||
&inlining_map,
|
||||
))
|
||||
|
|
Loading…
Add table
Reference in a new issue