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