Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't compute inlining status of mono items in advance. #112128

Merged
merged 1 commit into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 13 additions & 63 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::mir::interpret::{AllocId, ConstValue};
use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
Expand Down Expand Up @@ -220,78 +219,29 @@ pub struct InliningMap<'tcx> {
// The range selects elements within the `targets` vecs.
index: FxHashMap<MonoItem<'tcx>, Range<usize>>,
targets: Vec<MonoItem<'tcx>>,

// Contains one bit per mono item in the `targets` field. That bit
// is true if that mono item needs to be inlined into every CGU.
inlines: GrowableBitSet<usize>,
}

/// Struct to store mono items in each collecting and if they should
/// be inlined. We call `instantiation_mode` to get their inlining
/// status when inserting new elements, which avoids calling it in
/// `inlining_map.lock_mut()`. See the `collect_items_rec` implementation
/// below.
struct MonoItems<'tcx> {
// If this is false, we do not need to compute whether items
// will need to be inlined.
compute_inlining: bool,

// The TyCtxt used to determine whether the a item should
// be inlined.
tcx: TyCtxt<'tcx>,

// The collected mono items. The bool field in each element
// indicates whether this element should be inlined.
items: Vec<(Spanned<MonoItem<'tcx>>, bool /*inlined*/)>,
}

impl<'tcx> MonoItems<'tcx> {
#[inline]
fn push(&mut self, item: Spanned<MonoItem<'tcx>>) {
self.extend([item]);
}

#[inline]
fn extend<T: IntoIterator<Item = Spanned<MonoItem<'tcx>>>>(&mut self, iter: T) {
self.items.extend(iter.into_iter().map(|mono_item| {
let inlined = if !self.compute_inlining {
false
} else {
mono_item.node.instantiation_mode(self.tcx) == InstantiationMode::LocalCopy
};
(mono_item, inlined)
}))
}
}
type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>;

impl<'tcx> InliningMap<'tcx> {
fn new() -> InliningMap<'tcx> {
InliningMap {
index: FxHashMap::default(),
targets: Vec::new(),
inlines: GrowableBitSet::with_capacity(1024),
}
InliningMap { index: FxHashMap::default(), targets: Vec::new() }
}

fn record_accesses<'a>(
&mut self,
source: MonoItem<'tcx>,
new_targets: &'a [(Spanned<MonoItem<'tcx>>, bool)],
new_targets: &'a [Spanned<MonoItem<'tcx>>],
) where
'tcx: 'a,
{
let start_index = self.targets.len();
let new_items_count = new_targets.len();
let new_items_count_total = new_items_count + self.targets.len();

self.targets.reserve(new_items_count);
self.inlines.ensure(new_items_count_total);

for (i, (Spanned { node: mono_item, .. }, inlined)) in new_targets.into_iter().enumerate() {
for Spanned { node: mono_item, .. } in new_targets.into_iter() {
self.targets.push(*mono_item);
if *inlined {
self.inlines.insert(i + start_index);
}
}

let end_index = self.targets.len();
Expand All @@ -300,13 +250,14 @@ impl<'tcx> InliningMap<'tcx> {

/// Internally iterate over all items referenced by `source` which will be
/// made available for inlining.
pub fn with_inlining_candidates<F>(&self, source: MonoItem<'tcx>, mut f: F)
pub fn with_inlining_candidates<F>(&self, tcx: TyCtxt<'tcx>, source: MonoItem<'tcx>, mut f: F)
where
F: FnMut(MonoItem<'tcx>),
{
if let Some(range) = self.index.get(&source) {
for (i, candidate) in self.targets[range.clone()].iter().enumerate() {
if self.inlines.contains(range.start + i) {
for candidate in self.targets[range.clone()].iter() {
let is_inlined = candidate.instantiation_mode(tcx) == InstantiationMode::LocalCopy;
if is_inlined {
f(*candidate);
}
}
Expand Down Expand Up @@ -367,7 +318,7 @@ pub fn collect_crate_mono_items(
#[instrument(skip(tcx, mode), level = "debug")]
fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> {
debug!("collecting roots");
let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() };
let mut roots = Vec::new();

{
let entry_fn = tcx.entry_fn(());
Expand All @@ -393,9 +344,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
// whose predicates hold. Luckily, items that aren't instantiable
// can't actually be used, so we can just skip codegenning them.
roots
.items
.into_iter()
.filter_map(|(Spanned { node: mono_item, .. }, _)| {
.filter_map(|Spanned { node: mono_item, .. }| {
mono_item.is_instantiable(tcx).then_some(mono_item)
})
.collect()
Expand All @@ -417,7 +367,7 @@ fn collect_items_rec<'tcx>(
return;
}

let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() };
let mut neighbors = Vec::new();
let recursion_depth_reset;

//
Expand Down Expand Up @@ -542,9 +492,9 @@ fn collect_items_rec<'tcx>(
formatted_item,
});
}
inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items);
inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors);

for (neighbour, _) in neighbors.items {
for neighbour in neighbors {
collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map);
}

Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ fn place_inlined_mono_items<'tcx>(
// 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() {
follow_inlining(*root, cx.inlining_map, &mut reachable);
follow_inlining(cx.tcx, *root, cx.inlining_map, &mut reachable);
}

let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name());
Expand Down Expand Up @@ -478,6 +478,7 @@ fn place_inlined_mono_items<'tcx>(
return mono_item_placements;

fn follow_inlining<'tcx>(
tcx: TyCtxt<'tcx>,
mono_item: MonoItem<'tcx>,
inlining_map: &InliningMap<'tcx>,
visited: &mut FxHashSet<MonoItem<'tcx>>,
Expand All @@ -486,8 +487,8 @@ fn place_inlined_mono_items<'tcx>(
return;
}

inlining_map.with_inlining_candidates(mono_item, |target| {
follow_inlining(target, inlining_map, visited);
inlining_map.with_inlining_candidates(tcx, mono_item, |target| {
follow_inlining(tcx, target, inlining_map, visited);
});
}
}
Expand Down