]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / compiler / rustc_mir / src / transform / remove_noop_landing_pads.rs
1 use crate::transform::MirPass;
2 use crate::util::patch::MirPatch;
3 use rustc_index::bit_set::BitSet;
4 use rustc_middle::mir::*;
5 use rustc_middle::ty::TyCtxt;
6 use rustc_target::spec::PanicStrategy;
7
8 /// A pass that removes noop landing pads and replaces jumps to them with
9 /// `None`. This is important because otherwise LLVM generates terrible
10 /// code for these.
11 pub struct RemoveNoopLandingPads;
12
13 pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
14 if tcx.sess.panic_strategy() == PanicStrategy::Abort {
15 return;
16 }
17 debug!("remove_noop_landing_pads({:?})", body);
18
19 RemoveNoopLandingPads.remove_nop_landing_pads(body)
20 }
21
22 impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
23 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
24 remove_noop_landing_pads(tcx, body);
25 }
26 }
27
28 impl RemoveNoopLandingPads {
29 fn is_nop_landing_pad(
30 &self,
31 bb: BasicBlock,
32 body: &Body<'_>,
33 nop_landing_pads: &BitSet<BasicBlock>,
34 ) -> bool {
35 for stmt in &body[bb].statements {
36 match &stmt.kind {
37 StatementKind::FakeRead(..)
38 | StatementKind::StorageLive(_)
39 | StatementKind::StorageDead(_)
40 | StatementKind::AscribeUserType(..)
41 | StatementKind::Coverage(..)
42 | StatementKind::Nop => {
43 // These are all nops in a landing pad
44 }
45
46 StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => {
47 if place.as_local().is_some() {
48 // Writing to a local (e.g., a drop flag) does not
49 // turn a landing pad to a non-nop
50 } else {
51 return false;
52 }
53 }
54
55 StatementKind::Assign { .. }
56 | StatementKind::SetDiscriminant { .. }
57 | StatementKind::LlvmInlineAsm { .. }
58 | StatementKind::CopyNonOverlapping(..)
59 | StatementKind::Retag { .. } => {
60 return false;
61 }
62 }
63 }
64
65 let terminator = body[bb].terminator();
66 match terminator.kind {
67 TerminatorKind::Goto { .. }
68 | TerminatorKind::Resume
69 | TerminatorKind::SwitchInt { .. }
70 | TerminatorKind::FalseEdge { .. }
71 | TerminatorKind::FalseUnwind { .. } => {
72 terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
73 }
74 TerminatorKind::GeneratorDrop
75 | TerminatorKind::Yield { .. }
76 | TerminatorKind::Return
77 | TerminatorKind::Abort
78 | TerminatorKind::Unreachable
79 | TerminatorKind::Call { .. }
80 | TerminatorKind::Assert { .. }
81 | TerminatorKind::DropAndReplace { .. }
82 | TerminatorKind::Drop { .. }
83 | TerminatorKind::InlineAsm { .. } => false,
84 }
85 }
86
87 fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
88 // make sure there's a single resume block
89 let resume_block = {
90 let patch = MirPatch::new(body);
91 let resume_block = patch.resume_block();
92 patch.apply(body);
93 resume_block
94 };
95 debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
96
97 let mut jumps_folded = 0;
98 let mut landing_pads_removed = 0;
99 let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len());
100
101 // This is a post-order traversal, so that if A post-dominates B
102 // then A will be visited before B.
103 let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
104 for bb in postorder {
105 debug!(" processing {:?}", bb);
106 if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
107 if let Some(unwind_bb) = *unwind {
108 if nop_landing_pads.contains(unwind_bb) {
109 debug!(" removing noop landing pad");
110 landing_pads_removed += 1;
111 *unwind = None;
112 }
113 }
114 }
115
116 for target in body[bb].terminator_mut().successors_mut() {
117 if *target != resume_block && nop_landing_pads.contains(*target) {
118 debug!(" folding noop jump to {:?} to resume block", target);
119 *target = resume_block;
120 jumps_folded += 1;
121 }
122 }
123
124 let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
125 if is_nop_landing_pad {
126 nop_landing_pads.insert(bb);
127 }
128 debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
129 }
130
131 debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
132 }
133 }