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