rustc_mir_transform/
remove_noop_landing_pads.rs1use rustc_index::bit_set::DenseBitSet;
2use rustc_middle::mir::*;
3use rustc_middle::ty::{self, Instance, TyCtxt};
4use tracing::{debug, instrument};
5
6use crate::PassPolicy;
7use crate::patch::MirPatch;
8
9pub(super) struct RemoveNoopLandingPads;
13
14impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
15 fn policy(&self, sess: &rustc_session::Session) -> PassPolicy {
16 PassPolicy::optional_non_optimization(sess.panic_strategy().unwinds())
19 }
20
21 #[instrument(level = "debug", skip(self, _tcx, body))]
22 fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
23 let def_id = body.source.def_id();
24 debug!(?def_id);
25
26 let has_resume = body
28 .basic_blocks
29 .iter_enumerated()
30 .any(|(_bb, block)| matches!(block.terminator().kind, TerminatorKind::UnwindResume));
31 if !has_resume {
32 debug!("no resume block in MIR");
33 return;
34 }
35
36 let nop_landing_pads = find_noop_landing_pads(body, None);
37
38 if nop_landing_pads.is_empty() {
39 debug!("no nop landing pads in MIR");
40 return;
41 }
42
43 let resume_block = {
45 let mut patch = MirPatch::new(body);
46 let resume_block = patch.resume_block();
47 patch.apply(body);
48 resume_block
49 };
50 debug!(?resume_block);
51
52 let basic_blocks = body.basic_blocks.as_mut();
53 for (bb, bbdata) in basic_blocks.iter_enumerated_mut() {
54 debug!("processing {:?}", bb);
55
56 if let Some(unwind) = bbdata.terminator_mut().unwind_mut()
57 && let UnwindAction::Cleanup(unwind_bb) = *unwind
58 && nop_landing_pads.contains(unwind_bb)
59 {
60 debug!(" removing noop landing pad");
61 *unwind = UnwindAction::Continue;
62 }
63
64 bbdata.terminator_mut().successors_mut(|target| {
65 if *target != resume_block && nop_landing_pads.contains(*target) {
66 debug!(" folding noop jump to {:?} to resume block", target);
67 *target = resume_block;
68 }
69 });
70 }
71 }
72}
73
74impl RemoveNoopLandingPads {
75 fn is_nop_landing_pad<'tcx>(
76 &self,
77 bbdata: &BasicBlockData<'tcx>,
78 body: &Body<'tcx>,
79 nop_landing_pads: &DenseBitSet<BasicBlock>,
80 extra: Option<&ExtraInfo<'tcx>>,
81 ) -> bool {
82 for stmt in &bbdata.statements {
83 match &stmt.kind {
84 StatementKind::FakeRead(..)
85 | StatementKind::StorageLive(_)
86 | StatementKind::StorageDead(_)
87 | StatementKind::PlaceMention(..)
88 | StatementKind::AscribeUserType(..)
89 | StatementKind::Coverage(..)
90 | StatementKind::ConstEvalCounter
91 | StatementKind::BackwardIncompatibleDropHint { .. }
92 | StatementKind::Nop => {
93 }
95
96 StatementKind::Assign((place, Rvalue::Use(..) | Rvalue::Discriminant(_))) => {
97 if place.as_local().is_some() {
98 } else {
101 return false;
102 }
103 }
104
105 StatementKind::Assign { .. }
106 | StatementKind::SetDiscriminant { .. }
107 | StatementKind::Intrinsic(..) => {
108 return false;
109 }
110 }
111 }
112
113 let terminator = bbdata.terminator();
114 match terminator.kind {
115 TerminatorKind::Goto { .. }
116 | TerminatorKind::UnwindResume
117 | TerminatorKind::SwitchInt { .. }
118 | TerminatorKind::FalseEdge { .. }
119 | TerminatorKind::FalseUnwind { .. } => {
120 terminator.successors().all(|succ| nop_landing_pads.contains(succ))
121 }
122 TerminatorKind::Drop { place, .. } => {
123 if let Some(extra) = extra {
124 let ty = place.ty(body, extra.tcx).ty;
125 debug!("monomorphize: instance={:?}", extra.instance);
126 let ty = extra.instance.instantiate_mir_and_normalize_erasing_regions(
127 extra.tcx,
128 extra.typing_env,
129 ty::EarlyBinder::bind(extra.tcx, ty),
130 );
131 let drop_fn = Instance::resolve_drop_glue(extra.tcx, ty);
132 if let ty::InstanceKind::Shim(ty::ShimKind::DropGlue(_, None)) = drop_fn.def {
133 return terminator.successors().all(|succ| nop_landing_pads.contains(succ));
136 }
137 }
138
139 false
140 }
141 TerminatorKind::CoroutineDrop
142 | TerminatorKind::Yield { .. }
143 | TerminatorKind::Return
144 | TerminatorKind::UnwindTerminate(_)
145 | TerminatorKind::Unreachable
146 | TerminatorKind::Call { .. }
147 | TerminatorKind::TailCall { .. }
148 | TerminatorKind::Assert { .. }
149 | TerminatorKind::InlineAsm { .. } => false,
150 }
151 }
152}
153
154pub struct ExtraInfo<'tcx> {
158 pub tcx: TyCtxt<'tcx>,
159 pub instance: Instance<'tcx>,
160 pub typing_env: ty::TypingEnv<'tcx>,
161}
162
163pub fn find_noop_landing_pads<'tcx>(
164 body: &Body<'tcx>,
165 extra: Option<ExtraInfo<'tcx>>,
166) -> DenseBitSet<BasicBlock> {
167 let mut nop_landing_pads = DenseBitSet::new_empty(body.basic_blocks.len());
168
169 let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
172 for bb in postorder {
173 let is_nop_landing_pad = RemoveNoopLandingPads.is_nop_landing_pad(
174 &body.basic_blocks[bb],
175 body,
176 &nop_landing_pads,
177 extra.as_ref(),
178 );
179 if is_nop_landing_pad {
180 nop_landing_pads.insert(bb);
181 }
182 debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
183 }
184
185 nop_landing_pads
186}