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