]>
git.proxmox.com Git - rustc.git/blob - src/librustc_mir/transform/remove_noop_landing_pads.rs
3 use rustc_index
::bit_set
::BitSet
;
4 use crate::transform
::{MirPass, MirSource}
;
5 use crate::util
::patch
::MirPatch
;
7 /// A pass that removes noop landing pads and replaces jumps to them with
8 /// `None`. This is important because otherwise LLVM generates terrible
10 pub struct RemoveNoopLandingPads
;
12 pub fn remove_noop_landing_pads
<'tcx
>(tcx
: TyCtxt
<'tcx
>, body
: &mut BodyAndCache
<'tcx
>) {
13 if tcx
.sess
.no_landing_pads() {
16 debug
!("remove_noop_landing_pads({:?})", body
);
18 RemoveNoopLandingPads
.remove_nop_landing_pads(body
)
21 impl<'tcx
> MirPass
<'tcx
> for RemoveNoopLandingPads
{
22 fn run_pass(&self, tcx
: TyCtxt
<'tcx
>, _src
: MirSource
<'tcx
>, body
: &mut BodyAndCache
<'tcx
>) {
23 remove_noop_landing_pads(tcx
, body
);
27 impl RemoveNoopLandingPads
{
28 fn is_nop_landing_pad(
32 nop_landing_pads
: &BitSet
<BasicBlock
>,
34 for stmt
in &body
[bb
].statements
{
36 StatementKind
::FakeRead(..) |
37 StatementKind
::StorageLive(_
) |
38 StatementKind
::StorageDead(_
) |
39 StatementKind
::AscribeUserType(..) |
40 StatementKind
::Nop
=> {
41 // These are all nops in a landing pad
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
53 StatementKind
::Assign { .. }
|
54 StatementKind
::SetDiscriminant { .. }
|
55 StatementKind
::InlineAsm { .. }
|
56 StatementKind
::Retag { .. }
=> {
62 let terminator
= body
[bb
].terminator();
63 match terminator
.kind
{
64 TerminatorKind
::Goto { .. }
|
65 TerminatorKind
::Resume
|
66 TerminatorKind
::SwitchInt { .. }
|
67 TerminatorKind
::FalseEdges { .. }
|
68 TerminatorKind
::FalseUnwind { .. }
=> {
69 terminator
.successors().all(|&succ
| {
70 nop_landing_pads
.contains(succ
)
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 { .. }
=> {
87 fn remove_nop_landing_pads(&self, body
: &mut BodyAndCache
<'_
>) {
88 // make sure there's a single resume block
90 let patch
= MirPatch
::new(body
);
91 let resume_block
= patch
.resume_block();
95 debug
!("remove_noop_landing_pads: resume block is {:?}", resume_block
);
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());
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 for target
in body
[bb
].terminator_mut().successors_mut() {
107 if *target
!= resume_block
&& nop_landing_pads
.contains(*target
) {
108 debug
!(" folding noop jump to {:?} to resume block", target
);
109 *target
= resume_block
;
114 match body
[bb
].terminator_mut().unwind_mut() {
116 if *unwind
== Some(resume_block
) {
117 debug
!(" removing noop landing pad");
119 landing_pads_removed
+= 1;
126 let is_nop_landing_pad
= self.is_nop_landing_pad(bb
, body
, &nop_landing_pads
);
127 if is_nop_landing_pad
{
128 nop_landing_pads
.insert(bb
);
130 debug
!(" is_nop_landing_pad({:?}) = {}", bb
, is_nop_landing_pad
);
133 debug
!("removed {:?} jumps and {:?} landing pads", jumps_folded
, landing_pads_removed
);