]>
Commit | Line | Data |
---|---|---|
ff7c6d11 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use rustc::ty::TyCtxt; | |
12 | use rustc::mir::*; | |
0bf4aa26 | 13 | use rustc_data_structures::bit_set::BitSet; |
ff7c6d11 XL |
14 | use transform::{MirPass, MirSource}; |
15 | use util::patch::MirPatch; | |
16 | ||
17 | /// A pass that removes no-op landing pads and replaces jumps to them with | |
18 | /// `None`. This is important because otherwise LLVM generates terrible | |
19 | /// code for these. | |
20 | pub struct RemoveNoopLandingPads; | |
21 | ||
2c00a5a8 XL |
22 | pub fn remove_noop_landing_pads<'a, 'tcx>( |
23 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
24 | mir: &mut Mir<'tcx>) | |
25 | { | |
26 | if tcx.sess.no_landing_pads() { | |
27 | return | |
28 | } | |
29 | debug!("remove_noop_landing_pads({:?})", mir); | |
30 | ||
31 | RemoveNoopLandingPads.remove_nop_landing_pads(mir) | |
32 | } | |
33 | ||
ff7c6d11 XL |
34 | impl MirPass for RemoveNoopLandingPads { |
35 | fn run_pass<'a, 'tcx>(&self, | |
36 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
37 | _src: MirSource, | |
38 | mir: &mut Mir<'tcx>) { | |
2c00a5a8 | 39 | remove_noop_landing_pads(tcx, mir); |
ff7c6d11 XL |
40 | } |
41 | } | |
42 | ||
43 | impl RemoveNoopLandingPads { | |
8faf50e0 XL |
44 | fn is_nop_landing_pad( |
45 | &self, | |
46 | bb: BasicBlock, | |
47 | mir: &Mir, | |
0bf4aa26 | 48 | nop_landing_pads: &BitSet<BasicBlock>, |
8faf50e0 | 49 | ) -> bool { |
ff7c6d11 XL |
50 | for stmt in &mir[bb].statements { |
51 | match stmt.kind { | |
0bf4aa26 | 52 | StatementKind::FakeRead(..) | |
ff7c6d11 XL |
53 | StatementKind::StorageLive(_) | |
54 | StatementKind::StorageDead(_) | | |
55 | StatementKind::EndRegion(_) | | |
b7449926 | 56 | StatementKind::AscribeUserType(..) | |
ff7c6d11 XL |
57 | StatementKind::Nop => { |
58 | // These are all nops in a landing pad (there's some | |
59 | // borrowck interaction between EndRegion and storage | |
60 | // instructions, but this should all run after borrowck). | |
61 | } | |
62 | ||
0bf4aa26 | 63 | StatementKind::Assign(Place::Local(_), box Rvalue::Use(_)) => { |
ff7c6d11 XL |
64 | // Writing to a local (e.g. a drop flag) does not |
65 | // turn a landing pad to a non-nop | |
66 | } | |
67 | ||
68 | StatementKind::Assign(_, _) | | |
69 | StatementKind::SetDiscriminant { .. } | | |
70 | StatementKind::InlineAsm { .. } | | |
71 | StatementKind::Validate { .. } => { | |
72 | return false; | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | let terminator = mir[bb].terminator(); | |
78 | match terminator.kind { | |
79 | TerminatorKind::Goto { .. } | | |
80 | TerminatorKind::Resume | | |
81 | TerminatorKind::SwitchInt { .. } | | |
2c00a5a8 XL |
82 | TerminatorKind::FalseEdges { .. } | |
83 | TerminatorKind::FalseUnwind { .. } => { | |
8faf50e0 XL |
84 | terminator.successors().all(|&succ| { |
85 | nop_landing_pads.contains(succ) | |
ff7c6d11 XL |
86 | }) |
87 | }, | |
88 | TerminatorKind::GeneratorDrop | | |
89 | TerminatorKind::Yield { .. } | | |
90 | TerminatorKind::Return | | |
91 | TerminatorKind::Abort | | |
92 | TerminatorKind::Unreachable | | |
93 | TerminatorKind::Call { .. } | | |
94 | TerminatorKind::Assert { .. } | | |
95 | TerminatorKind::DropAndReplace { .. } | | |
96 | TerminatorKind::Drop { .. } => { | |
97 | false | |
98 | } | |
99 | } | |
100 | } | |
101 | ||
102 | fn remove_nop_landing_pads(&self, mir: &mut Mir) { | |
103 | // make sure there's a single resume block | |
104 | let resume_block = { | |
105 | let patch = MirPatch::new(mir); | |
106 | let resume_block = patch.resume_block(); | |
107 | patch.apply(mir); | |
108 | resume_block | |
109 | }; | |
110 | debug!("remove_noop_landing_pads: resume block is {:?}", resume_block); | |
111 | ||
112 | let mut jumps_folded = 0; | |
113 | let mut landing_pads_removed = 0; | |
0bf4aa26 | 114 | let mut nop_landing_pads = BitSet::new_empty(mir.basic_blocks().len()); |
ff7c6d11 XL |
115 | |
116 | // This is a post-order traversal, so that if A post-dominates B | |
117 | // then A will be visited before B. | |
118 | let postorder: Vec<_> = traversal::postorder(mir).map(|(bb, _)| bb).collect(); | |
119 | for bb in postorder { | |
120 | debug!(" processing {:?}", bb); | |
121 | for target in mir[bb].terminator_mut().successors_mut() { | |
8faf50e0 | 122 | if *target != resume_block && nop_landing_pads.contains(*target) { |
ff7c6d11 XL |
123 | debug!(" folding noop jump to {:?} to resume block", target); |
124 | *target = resume_block; | |
125 | jumps_folded += 1; | |
126 | } | |
127 | } | |
128 | ||
129 | match mir[bb].terminator_mut().unwind_mut() { | |
130 | Some(unwind) => { | |
131 | if *unwind == Some(resume_block) { | |
132 | debug!(" removing noop landing pad"); | |
133 | jumps_folded -= 1; | |
134 | landing_pads_removed += 1; | |
135 | *unwind = None; | |
136 | } | |
137 | } | |
138 | _ => {} | |
139 | } | |
140 | ||
141 | let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads); | |
142 | if is_nop_landing_pad { | |
8faf50e0 | 143 | nop_landing_pads.insert(bb); |
ff7c6d11 XL |
144 | } |
145 | debug!(" is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad); | |
146 | } | |
147 | ||
148 | debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed); | |
149 | } | |
150 | } |