Skip to content

Commit e287ddb

Browse files
committed
Only collect mono items from reachable blocks
1 parent 395f780 commit e287ddb

File tree

6 files changed

+87
-56
lines changed

6 files changed

+87
-56
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4374,6 +4374,7 @@ dependencies = [
43744374
"rustc_errors",
43754375
"rustc_fluent_macro",
43764376
"rustc_hir",
4377+
"rustc_index",
43774378
"rustc_macros",
43784379
"rustc_middle",
43794380
"rustc_session",

compiler/rustc_codegen_ssa/src/mir/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
257257
// Apply debuginfo to the newly allocated locals.
258258
fx.debug_introduce_locals(&mut start_bx);
259259

260-
let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance);
260+
let reachable_blocks = traversal::reachable_blocks_in_mono(mir, cx.tcx(), instance);
261261

262262
// The builders will be created separately for each basic block at `codegen_block`.
263263
// So drop the builder of `start_llbb` to avoid having two at the same time.
@@ -268,9 +268,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
268268
if reachable_blocks.contains(bb) {
269269
fx.codegen_block(bb);
270270
} else {
271-
// This may have references to things we didn't monomorphize, so we
272-
// don't actually codegen the body. We still create the block so
273-
// terminators in other blocks can reference it without worry.
271+
// We want to skip this block, because it's not reachable. But we still create
272+
// the block so terminators in other blocks can reference it.
274273
fx.codegen_block_as_unreachable(bb);
275274
}
276275
}

compiler/rustc_middle/src/mir/mod.rs

-52
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ pub use rustc_ast::Mutability;
3030
use rustc_data_structures::fx::FxHashMap;
3131
use rustc_data_structures::fx::FxHashSet;
3232
use rustc_data_structures::graph::dominators::Dominators;
33-
use rustc_data_structures::stack::ensure_sufficient_stack;
3433
use rustc_index::bit_set::BitSet;
3534
use rustc_index::{Idx, IndexSlice, IndexVec};
3635
use rustc_serialize::{Decodable, Encodable};
@@ -687,57 +686,6 @@ impl<'tcx> Body<'tcx> {
687686
self.injection_phase.is_some()
688687
}
689688

690-
/// Finds which basic blocks are actually reachable for a specific
691-
/// monomorphization of this body.
692-
///
693-
/// This is allowed to have false positives; just because this says a block
694-
/// is reachable doesn't mean that's necessarily true. It's thus always
695-
/// legal for this to return a filled set.
696-
///
697-
/// Regardless, the [`BitSet::domain_size`] of the returned set will always
698-
/// exactly match the number of blocks in the body so that `contains`
699-
/// checks can be done without worrying about panicking.
700-
///
701-
/// This is mostly useful because it lets us skip lowering the `false` side
702-
/// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`.
703-
pub fn reachable_blocks_in_mono(
704-
&self,
705-
tcx: TyCtxt<'tcx>,
706-
instance: Instance<'tcx>,
707-
) -> BitSet<BasicBlock> {
708-
let mut set = BitSet::new_empty(self.basic_blocks.len());
709-
self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK);
710-
set
711-
}
712-
713-
fn reachable_blocks_in_mono_from(
714-
&self,
715-
tcx: TyCtxt<'tcx>,
716-
instance: Instance<'tcx>,
717-
set: &mut BitSet<BasicBlock>,
718-
bb: BasicBlock,
719-
) {
720-
if !set.insert(bb) {
721-
return;
722-
}
723-
724-
let data = &self.basic_blocks[bb];
725-
726-
if let Some((bits, targets)) = Self::try_const_mono_switchint(tcx, instance, data) {
727-
let target = targets.target_for_value(bits);
728-
ensure_sufficient_stack(|| {
729-
self.reachable_blocks_in_mono_from(tcx, instance, set, target)
730-
});
731-
return;
732-
}
733-
734-
for target in data.terminator().successors() {
735-
ensure_sufficient_stack(|| {
736-
self.reachable_blocks_in_mono_from(tcx, instance, set, target)
737-
});
738-
}
739-
}
740-
741689
/// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the
742690
/// dimscriminant in monomorphization, we return the discriminant bits and the
743691
/// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator.

compiler/rustc_middle/src/mir/traversal.rs

+69
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,72 @@ pub fn reverse_postorder<'a, 'tcx>(
279279
{
280280
body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb]))
281281
}
282+
283+
/// Finds which basic blocks are actually reachable for a specific
284+
/// monomorphization of this body.
285+
///
286+
/// This is allowed to have false positives; just because this says a block
287+
/// is reachable doesn't mean that's necessarily true. It's thus always
288+
/// legal for this to return a filled set.
289+
///
290+
/// Regardless, the [`BitSet::domain_size`] of the returned set will always
291+
/// exactly match the number of blocks in the body so that `contains`
292+
/// checks can be done without worrying about panicking.
293+
///
294+
/// This is mostly useful because it lets us skip lowering the `false` side
295+
/// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`.
296+
pub fn reachable_blocks_in_mono<'tcx>(
297+
body: &Body<'tcx>,
298+
tcx: TyCtxt<'tcx>,
299+
instance: Instance<'tcx>,
300+
) -> BitSet<BasicBlock> {
301+
let mut visitor = MonoReachable {
302+
body,
303+
tcx,
304+
instance,
305+
worklist: Vec::new(),
306+
visited: BitSet::new_empty(body.basic_blocks.len()),
307+
};
308+
309+
visitor.visited.insert(START_BLOCK);
310+
visitor.visit(START_BLOCK);
311+
312+
while let Some(bb) = visitor.worklist.pop() {
313+
if visitor.visited.insert(bb) {
314+
visitor.visit(bb);
315+
}
316+
}
317+
318+
visitor.visited
319+
}
320+
321+
struct MonoReachable<'a, 'tcx> {
322+
body: &'a Body<'tcx>,
323+
tcx: TyCtxt<'tcx>,
324+
instance: Instance<'tcx>,
325+
worklist: Vec<BasicBlock>,
326+
visited: BitSet<BasicBlock>,
327+
}
328+
329+
impl<'a, 'tcx> MonoReachable<'a, 'tcx> {
330+
fn visit(&mut self, bb: BasicBlock) {
331+
let block = &self.body.basic_blocks[bb];
332+
333+
if let Some((bits, targets)) =
334+
Body::try_const_mono_switchint(self.tcx, self.instance, block)
335+
{
336+
let target = targets.target_for_value(bits);
337+
self.push(target);
338+
} else {
339+
for target in block.terminator().successors() {
340+
self.push(target);
341+
}
342+
}
343+
}
344+
345+
fn push(&mut self, bb: BasicBlock) {
346+
if !self.visited.contains(bb) {
347+
self.worklist.push(bb);
348+
}
349+
}
350+
}

compiler/rustc_monomorphize/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
99
rustc_errors = { path = "../rustc_errors" }
1010
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1111
rustc_hir = { path = "../rustc_hir" }
12+
rustc_index = { path = "../rustc_index" }
1213
rustc_macros = { path = "../rustc_macros" }
1314
rustc_middle = { path = "../rustc_middle" }
1415
rustc_session = { path = "../rustc_session" }

compiler/rustc_monomorphize/src/collector.rs

+13
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ use rustc_hir as hir;
211211
use rustc_hir::def::DefKind;
212212
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
213213
use rustc_hir::lang_items::LangItem;
214+
use rustc_index::bit_set::BitSet;
214215
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
215216
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
216217
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
@@ -671,6 +672,7 @@ struct MirUsedCollector<'a, 'tcx> {
671672
visiting_call_terminator: bool,
672673
/// Set of functions for which it is OK to move large data into.
673674
skip_move_check_fns: Option<Vec<DefId>>,
675+
reachable_blocks: BitSet<mir::BasicBlock>,
674676
}
675677

676678
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -831,6 +833,12 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
831833
}
832834

833835
impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
836+
fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
837+
if self.reachable_blocks.contains(block) {
838+
self.super_basic_block_data(block, data)
839+
}
840+
}
841+
834842
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
835843
debug!("visiting rvalue {:?}", *rvalue);
836844

@@ -1411,6 +1419,11 @@ fn collect_items_of_instance<'tcx>(
14111419
move_size_spans: vec![],
14121420
visiting_call_terminator: false,
14131421
skip_move_check_fns: None,
1422+
reachable_blocks: if mode == CollectionMode::UsedItems {
1423+
mir::traversal::reachable_blocks_in_mono(body, tcx, instance)
1424+
} else {
1425+
BitSet::new_filled(body.basic_blocks.len())
1426+
},
14141427
};
14151428

14161429
if mode == CollectionMode::UsedItems {

0 commit comments

Comments
 (0)