]>
git.proxmox.com Git - rustc.git/blob - compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
1 use crate::transform
::MirPass
;
2 use crate::util
::patch
::MirPatch
;
3 use rustc_index
::bit_set
::BitSet
;
4 use rustc_middle
::mir
::*;
5 use rustc_middle
::ty
::TyCtxt
;
6 use rustc_target
::spec
::PanicStrategy
;
8 /// A pass that removes noop landing pads and replaces jumps to them with
9 /// `None`. This is important because otherwise LLVM generates terrible
11 pub struct RemoveNoopLandingPads
;
13 pub fn remove_noop_landing_pads
<'tcx
>(tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
14 if tcx
.sess
.panic_strategy() == PanicStrategy
::Abort
{
17 debug
!("remove_noop_landing_pads({:?})", body
);
19 RemoveNoopLandingPads
.remove_nop_landing_pads(body
)
22 impl<'tcx
> MirPass
<'tcx
> for RemoveNoopLandingPads
{
23 fn run_pass(&self, tcx
: TyCtxt
<'tcx
>, body
: &mut Body
<'tcx
>) {
24 remove_noop_landing_pads(tcx
, body
);
28 impl RemoveNoopLandingPads
{
29 fn is_nop_landing_pad(
33 nop_landing_pads
: &BitSet
<BasicBlock
>,
35 for stmt
in &body
[bb
].statements
{
37 StatementKind
::FakeRead(..)
38 | StatementKind
::StorageLive(_
)
39 | StatementKind
::StorageDead(_
)
40 | StatementKind
::AscribeUserType(..)
41 | StatementKind
::Coverage(..)
42 | StatementKind
::Nop
=> {
43 // These are all nops in a landing pad
46 StatementKind
::Assign(box (place
, Rvalue
::Use(_
) | Rvalue
::Discriminant(_
))) => {
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
55 StatementKind
::Assign { .. }
56 | StatementKind
::SetDiscriminant { .. }
57 | StatementKind
::LlvmInlineAsm { .. }
58 | StatementKind
::CopyNonOverlapping(..)
59 | StatementKind
::Retag { .. }
=> {
65 let terminator
= body
[bb
].terminator();
66 match terminator
.kind
{
67 TerminatorKind
::Goto { .. }
68 | TerminatorKind
::Resume
69 | TerminatorKind
::SwitchInt { .. }
70 | TerminatorKind
::FalseEdge { .. }
71 | TerminatorKind
::FalseUnwind { .. }
=> {
72 terminator
.successors().all(|&succ
| nop_landing_pads
.contains(succ
))
74 TerminatorKind
::GeneratorDrop
75 | TerminatorKind
::Yield { .. }
76 | TerminatorKind
::Return
77 | TerminatorKind
::Abort
78 | TerminatorKind
::Unreachable
79 | TerminatorKind
::Call { .. }
80 | TerminatorKind
::Assert { .. }
81 | TerminatorKind
::DropAndReplace { .. }
82 | TerminatorKind
::Drop { .. }
83 | TerminatorKind
::InlineAsm { .. }
=> false,
87 fn remove_nop_landing_pads(&self, body
: &mut Body
<'_
>) {
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 if let Some(unwind
) = body
[bb
].terminator_mut().unwind_mut() {
107 if let Some(unwind_bb
) = *unwind
{
108 if nop_landing_pads
.contains(unwind_bb
) {
109 debug
!(" removing noop landing pad");
110 landing_pads_removed
+= 1;
116 for target
in body
[bb
].terminator_mut().successors_mut() {
117 if *target
!= resume_block
&& nop_landing_pads
.contains(*target
) {
118 debug
!(" folding noop jump to {:?} to resume block", target
);
119 *target
= resume_block
;
124 let is_nop_landing_pad
= self.is_nop_landing_pad(bb
, body
, &nop_landing_pads
);
125 if is_nop_landing_pad
{
126 nop_landing_pads
.insert(bb
);
128 debug
!(" is_nop_landing_pad({:?}) = {}", bb
, is_nop_landing_pad
);
131 debug
!("removed {:?} jumps and {:?} landing pads", jumps_folded
, landing_pads_removed
);