Skip to content

Commit e8dab79

Browse files
committed
Add post-mono passes to make mono-reachable analysis more accurate
1 parent ebe9b00 commit e8dab79

File tree

41 files changed

+456
-562
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+456
-562
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4207,7 +4207,6 @@ dependencies = [
42074207
name = "rustc_monomorphize"
42084208
version = "0.0.0"
42094209
dependencies = [
4210-
"rustc_abi",
42114210
"rustc_ast",
42124211
"rustc_attr_data_structures",
42134212
"rustc_data_structures",

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub(crate) fn codegen_fn<'tcx>(
4040
let symbol_name = tcx.symbol_name(instance).name.to_string();
4141
let _timer = tcx.prof.generic_activity_with_arg("codegen fn", &*symbol_name);
4242

43-
let mir = tcx.instance_mir(instance.def);
43+
let mir = tcx.codegen_mir(instance);
4444
let _mir_guard = crate::PrintOnPanic(|| {
4545
let mut buf = Vec::new();
4646
with_no_trimmed_paths!({
@@ -282,19 +282,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
282282
.generic_activity("codegen prelude")
283283
.run(|| crate::abi::codegen_fn_prelude(fx, start_block));
284284

285-
let reachable_blocks = traversal::mono_reachable_as_bitset(fx.mir, fx.tcx, fx.instance);
286-
287285
for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() {
288286
let block = fx.get_block(bb);
289287
fx.bcx.switch_to_block(block);
290288

291-
if !reachable_blocks.contains(bb) {
292-
// We want to skip this block, because it's not reachable. But we still create
293-
// the block so terminators in other blocks can reference it.
294-
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
295-
continue;
296-
}
297-
298289
if bb_data.is_cleanup {
299290
// Unwinding after panicking is not supported
300291
continue;

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
416416
// release builds.
417417
info!("codegen_instance({})", instance);
418418

419-
mir::codegen_mir::<Bx>(cx, instance);
419+
mir::lower_mir::<Bx>(cx, instance);
420420
}
421421

422422
pub fn codegen_global_asm<'tcx, Cx>(cx: &mut Cx, item_id: ItemId)

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,16 +1339,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13391339
}
13401340
}
13411341

1342-
pub(crate) fn codegen_block_as_unreachable(&mut self, bb: mir::BasicBlock) {
1343-
let llbb = match self.try_llbb(bb) {
1344-
Some(llbb) => llbb,
1345-
None => return,
1346-
};
1347-
let bx = &mut Bx::build(self.cx, llbb);
1348-
debug!("codegen_block_as_unreachable({:?})", bb);
1349-
bx.unreachable();
1350-
}
1351-
13521342
fn codegen_terminator(
13531343
&mut self,
13541344
bx: &mut Bx,

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
126126
where
127127
T: Copy + TypeFoldable<TyCtxt<'tcx>>,
128128
{
129-
debug!("monomorphize: self.instance={:?}", self.instance);
130-
self.instance.instantiate_mir_and_normalize_erasing_regions(
131-
self.cx.tcx(),
132-
self.cx.typing_env(),
133-
ty::EarlyBinder::bind(value),
134-
)
129+
value
135130
}
136131
}
137132

@@ -164,7 +159,7 @@ impl<'tcx, V: CodegenObject> LocalRef<'tcx, V> {
164159
///////////////////////////////////////////////////////////////////////////
165160

166161
#[instrument(level = "debug", skip(cx))]
167-
pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
162+
pub fn lower_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
168163
cx: &'a Bx::CodegenCx,
169164
instance: Instance<'tcx>,
170165
) {
@@ -173,7 +168,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
173168
let tcx = cx.tcx();
174169
let llfn = cx.get_fn(instance);
175170

176-
let mut mir = tcx.instance_mir(instance.def);
171+
let mut mir = tcx.codegen_mir(instance);
177172

178173
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
179174
debug!("fn_abi: {:?}", fn_abi);
@@ -238,7 +233,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
238233
fx.compute_per_local_var_debug_info(&mut start_bx).unzip();
239234
fx.per_local_var_debug_info = per_local_var_debug_info;
240235

241-
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, tcx, instance);
236+
let traversal_order: Vec<_> =
237+
traversal::reverse_postorder(mir).map(|(block, _data)| block).collect();
242238
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
243239

244240
// Allocate variable and temp allocas
@@ -298,20 +294,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
298294
// So drop the builder of `start_llbb` to avoid having two at the same time.
299295
drop(start_bx);
300296

301-
let mut unreached_blocks = DenseBitSet::new_filled(mir.basic_blocks.len());
302297
// Codegen the body of each reachable block using our reverse postorder list.
303298
for bb in traversal_order {
304299
fx.codegen_block(bb);
305-
unreached_blocks.remove(bb);
306-
}
307-
308-
// FIXME: These empty unreachable blocks are *mostly* a waste. They are occasionally
309-
// targets for a SwitchInt terminator, but the reimplementation of the mono-reachable
310-
// simplification in SwitchInt lowering sometimes misses cases that
311-
// mono_reachable_reverse_postorder manages to figure out.
312-
// The solution is to do something like post-mono GVN. But for now we have this hack.
313-
for bb in unreached_blocks.iter() {
314-
fx.codegen_block_as_unreachable(bb);
315300
}
316301
}
317302

compiler/rustc_middle/src/mir/basic_blocks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<'tcx> BasicBlocks<'tcx> {
8080
#[inline]
8181
pub fn reverse_postorder(&self) -> &[BasicBlock] {
8282
self.cache.reverse_postorder.get_or_init(|| {
83-
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, None).collect();
83+
let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect();
8484
rpo.reverse();
8585
rpo
8686
})

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 6 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ use crate::mir::interpret::{AllocRange, Scalar};
3333
use crate::ty::codec::{TyDecoder, TyEncoder};
3434
use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
3535
use crate::ty::{
36-
self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypeVisitableExt,
37-
TypingEnv, UserTypeAnnotationIndex,
36+
self, GenericArg, GenericArgsRef, InstanceKind, List, Ty, TyCtxt, TypeVisitableExt, TypingEnv,
37+
UserTypeAnnotationIndex,
3838
};
3939

4040
mod basic_blocks;
@@ -375,6 +375,8 @@ pub struct Body<'tcx> {
375375
#[type_foldable(identity)]
376376
#[type_visitable(ignore)]
377377
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
378+
379+
pub is_codegen_mir: bool,
378380
}
379381

380382
impl<'tcx> Body<'tcx> {
@@ -418,6 +420,7 @@ impl<'tcx> Body<'tcx> {
418420
tainted_by_errors,
419421
coverage_info_hi: None,
420422
function_coverage_info: None,
423+
is_codegen_mir: false,
421424
};
422425
body.is_polymorphic = body.has_non_region_param();
423426
body
@@ -449,6 +452,7 @@ impl<'tcx> Body<'tcx> {
449452
tainted_by_errors: None,
450453
coverage_info_hi: None,
451454
function_coverage_info: None,
455+
is_codegen_mir: false,
452456
};
453457
body.is_polymorphic = body.has_non_region_param();
454458
body
@@ -633,74 +637,6 @@ impl<'tcx> Body<'tcx> {
633637
self.injection_phase.is_some()
634638
}
635639

636-
/// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the
637-
/// discriminant in monomorphization, we return the discriminant bits and the
638-
/// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator.
639-
fn try_const_mono_switchint<'a>(
640-
tcx: TyCtxt<'tcx>,
641-
instance: Instance<'tcx>,
642-
block: &'a BasicBlockData<'tcx>,
643-
) -> Option<(u128, &'a SwitchTargets)> {
644-
// There are two places here we need to evaluate a constant.
645-
let eval_mono_const = |constant: &ConstOperand<'tcx>| {
646-
// FIXME(#132279): what is this, why are we using an empty environment here.
647-
let typing_env = ty::TypingEnv::fully_monomorphized();
648-
let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions(
649-
tcx,
650-
typing_env,
651-
crate::ty::EarlyBinder::bind(constant.const_),
652-
);
653-
mono_literal.try_eval_bits(tcx, typing_env)
654-
};
655-
656-
let TerminatorKind::SwitchInt { discr, targets } = &block.terminator().kind else {
657-
return None;
658-
};
659-
660-
// If this is a SwitchInt(const _), then we can just evaluate the constant and return.
661-
let discr = match discr {
662-
Operand::Constant(constant) => {
663-
let bits = eval_mono_const(constant)?;
664-
return Some((bits, targets));
665-
}
666-
Operand::Move(place) | Operand::Copy(place) => place,
667-
};
668-
669-
// MIR for `if false` actually looks like this:
670-
// _1 = const _
671-
// SwitchInt(_1)
672-
//
673-
// And MIR for if intrinsics::ub_checks() looks like this:
674-
// _1 = UbChecks()
675-
// SwitchInt(_1)
676-
//
677-
// So we're going to try to recognize this pattern.
678-
//
679-
// If we have a SwitchInt on a non-const place, we find the most recent statement that
680-
// isn't a storage marker. If that statement is an assignment of a const to our
681-
// discriminant place, we evaluate and return the const, as if we've const-propagated it
682-
// into the SwitchInt.
683-
684-
let last_stmt = block.statements.iter().rev().find(|stmt| {
685-
!matches!(stmt.kind, StatementKind::StorageDead(_) | StatementKind::StorageLive(_))
686-
})?;
687-
688-
let (place, rvalue) = last_stmt.kind.as_assign()?;
689-
690-
if discr != place {
691-
return None;
692-
}
693-
694-
match rvalue {
695-
Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)),
696-
Rvalue::Use(Operand::Constant(constant)) => {
697-
let bits = eval_mono_const(constant)?;
698-
Some((bits, targets))
699-
}
700-
_ => None,
701-
}
702-
}
703-
704640
/// For a `Location` in this scope, determine what the "caller location" at that point is. This
705641
/// is interesting because of inlining: the `#[track_caller]` attribute of inlined functions
706642
/// must be honored. Falls back to the `tracked_caller` value for `#[track_caller]` functions,
@@ -1381,19 +1317,6 @@ impl<'tcx> BasicBlockData<'tcx> {
13811317
pub fn is_empty_unreachable(&self) -> bool {
13821318
self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable)
13831319
}
1384-
1385-
/// Like [`Terminator::successors`] but tries to use information available from the [`Instance`]
1386-
/// to skip successors like the `false` side of an `if const {`.
1387-
///
1388-
/// This is used to implement [`traversal::mono_reachable`] and
1389-
/// [`traversal::mono_reachable_reverse_postorder`].
1390-
pub fn mono_successors(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Successors<'_> {
1391-
if let Some((bits, targets)) = Body::try_const_mono_switchint(tcx, instance, self) {
1392-
targets.successors_for_value(bits)
1393-
} else {
1394-
self.terminator().successors()
1395-
}
1396-
}
13971320
}
13981321

13991322
///////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)