Skip to main content

rustc_codegen_ssa/mir/
analyze.rs

1//! An analysis to determine which locals require allocas and
2//! which do not.
3
4use rustc_abi as abi;
5use rustc_data_structures::graph::dominators::Dominators;
6use rustc_index::bit_set::DenseBitSet;
7use rustc_index::{IndexSlice, IndexVec};
8use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
9use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
10use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
11use rustc_middle::{bug, span_bug, ty};
12use tracing::debug;
13
14use super::FunctionCx;
15use crate::traits::*;
16
17pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
18    fx: &FunctionCx<'a, 'tcx, Bx>,
19    traversal_order: &[mir::BasicBlock],
20) -> DenseBitSet<mir::Local> {
21    let mir = fx.mir;
22    let dominators = mir.basic_blocks.dominators();
23    let locals = mir
24        .local_decls
25        .iter()
26        .map(|decl| {
27            let ty = fx.monomorphize(decl.ty);
28            let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
29            if layout.is_zst() { LocalKind::ZST } else { LocalKind::Unused }
30        })
31        .collect();
32
33    let mut analyzer = LocalAnalyzer { fx, dominators, locals };
34
35    // Arguments get assigned to by means of the function being called
36    for arg in mir.args_iter() {
37        analyzer.define(arg, DefLocation::Argument);
38    }
39
40    // If there exists a local definition that dominates all uses of that local,
41    // the definition should be visited first. Traverse blocks in an order that
42    // is a topological sort of dominance partial order.
43    for bb in traversal_order.iter().copied() {
44        let data = &mir.basic_blocks[bb];
45        analyzer.visit_basic_block_data(bb, data);
46    }
47
48    let mut non_ssa_locals = DenseBitSet::new_empty(analyzer.locals.len());
49    for (local, kind) in analyzer.locals.iter_enumerated() {
50        if #[allow(non_exhaustive_omitted_patterns)] match kind {
    LocalKind::Memory => true,
    _ => false,
}matches!(kind, LocalKind::Memory) {
51            non_ssa_locals.insert(local);
52        }
53    }
54
55    non_ssa_locals
56}
57
58#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LocalKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            LocalKind::ZST => ::core::fmt::Formatter::write_str(f, "ZST"),
            LocalKind::Memory =>
                ::core::fmt::Formatter::write_str(f, "Memory"),
            LocalKind::Unused =>
                ::core::fmt::Formatter::write_str(f, "Unused"),
            LocalKind::SSA(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "SSA",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for LocalKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for LocalKind {
    #[inline]
    fn clone(&self) -> LocalKind {
        let _: ::core::clone::AssertParamIsClone<DefLocation>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for LocalKind {
    #[inline]
    fn eq(&self, other: &LocalKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (LocalKind::SSA(__self_0), LocalKind::SSA(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for LocalKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<DefLocation>;
    }
}Eq)]
59enum LocalKind {
60    ZST,
61    /// A local that requires an alloca.
62    Memory,
63    /// A scalar or a scalar pair local that is neither defined nor used.
64    Unused,
65    /// A scalar or a scalar pair local with a single definition that dominates all uses.
66    SSA(DefLocation),
67}
68
69struct LocalAnalyzer<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> {
70    fx: &'a FunctionCx<'b, 'tcx, Bx>,
71    dominators: &'a Dominators<mir::BasicBlock>,
72    locals: IndexVec<mir::Local, LocalKind>,
73}
74
75impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> {
76    fn define(&mut self, local: mir::Local, location: DefLocation) {
77        let fx = self.fx;
78        let kind = &mut self.locals[local];
79        let decl = &fx.mir.local_decls[local];
80        match *kind {
81            LocalKind::ZST => {}
82            LocalKind::Memory => {}
83            LocalKind::Unused => {
84                let ty = fx.monomorphize(decl.ty);
85                let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
86                *kind = if let abi::BackendRepr::Memory { .. } = layout.backend_repr {
87                    LocalKind::Memory
88                } else {
89                    LocalKind::SSA(location)
90                };
91            }
92            LocalKind::SSA(_) => *kind = LocalKind::Memory,
93        }
94    }
95
96    fn process_place(
97        &mut self,
98        place_ref: &mir::PlaceRef<'tcx>,
99        context: PlaceContext,
100        location: Location,
101    ) {
102        if !place_ref.projection.is_empty() {
103            const COPY_CONTEXT: PlaceContext =
104                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
105
106            // `PlaceElem::Index` is the only variant that can mention other `Local`s,
107            // so check for those up-front before any potential short-circuits.
108            for elem in place_ref.projection {
109                if let mir::PlaceElem::Index(index_local) = *elem {
110                    self.visit_local(index_local, COPY_CONTEXT, location);
111                }
112            }
113
114            // If our local is already memory, nothing can make it *more* memory
115            // so we don't need to bother checking the projections further.
116            if self.locals[place_ref.local] == LocalKind::Memory {
117                return;
118            }
119
120            if place_ref.is_indirect_first_projection() {
121                // If this starts with a `Deref`, we only need to record a read of the
122                // pointer being dereferenced, as all the subsequent projections are
123                // working on a place which is always supported. (And because we're
124                // looking at codegen MIR, it can only happen as the first projection.)
125                self.visit_local(place_ref.local, COPY_CONTEXT, location);
126                return;
127            }
128
129            if context.is_mutating_use() {
130                // If it's a mutating use it doesn't matter what the projections are,
131                // if there are *any* then we need a place to write. (For example,
132                // `_1 = Foo()` works in SSA but `_2.0 = Foo()` does not.)
133                let mut_projection = PlaceContext::MutatingUse(MutatingUseContext::Projection);
134                self.visit_local(place_ref.local, mut_projection, location);
135                return;
136            }
137
138            // Scan through to ensure the only projections are those which
139            // `FunctionCx::maybe_codegen_consume_direct` can handle.
140            let base_ty = self.fx.monomorphized_place_ty(mir::PlaceRef::from(place_ref.local));
141            let mut layout = self.fx.cx.layout_of(base_ty);
142            for elem in place_ref.projection {
143                layout = match *elem {
144                    mir::PlaceElem::Field(fidx, ..) => layout.field(self.fx.cx, fidx.as_usize()),
145                    mir::PlaceElem::Downcast(_, vidx)
146                        if let abi::Variants::Single { index: single_variant } =
147                            layout.variants
148                            && vidx == single_variant =>
149                    {
150                        layout.for_variant(self.fx.cx, vidx)
151                    }
152                    _ => {
153                        self.locals[place_ref.local] = LocalKind::Memory;
154                        return;
155                    }
156                }
157            }
158            if true {
    if !layout.is_ssa_standalone() {
        {
            ::core::panicking::panic_fmt(format_args!("Post-projection {0:?} layout should be non-Ref, but it\'s {1:?}",
                    place_ref, layout));
        }
    };
};debug_assert!(
159                layout.is_ssa_standalone(),
160                "Post-projection {place_ref:?} layout should be non-Ref, but it's {layout:?}",
161            );
162        }
163
164        // Even with supported projections, we still need to have `visit_local`
165        // check for things that can't be done in SSA (like `SharedBorrow`).
166        self.visit_local(place_ref.local, context, location);
167    }
168}
169
170impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer<'a, 'b, 'tcx, Bx> {
171    fn visit_assign(
172        &mut self,
173        place: &mir::Place<'tcx>,
174        rvalue: &mir::Rvalue<'tcx>,
175        location: Location,
176    ) {
177        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:177",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(177u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_assign(place={0:?}, rvalue={1:?})",
                                                    place, rvalue) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
178
179        if let Some(local) = place.as_local() {
180            self.define(local, DefLocation::Assignment(location));
181        } else {
182            self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
183        }
184
185        self.visit_rvalue(rvalue, location);
186    }
187
188    fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
189        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:189",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(189u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_place(place={0:?}, context={1:?})",
                                                    place, context) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("visit_place(place={:?}, context={:?})", place, context);
190        self.process_place(&place.as_ref(), context, location);
191    }
192
193    fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) {
194        match context {
195            PlaceContext::MutatingUse(MutatingUseContext::Call) => {
196                let call = location.block;
197                let TerminatorKind::Call { target, func, .. } =
198                    &self.fx.mir.basic_blocks[call].terminator().kind
199                else {
200                    ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
201                };
202                let tcx = self.fx.cx.tcx();
203                let func_ty = func.ty(&self.fx.mir.local_decls, tcx);
204                if let ty::FnDef(def_id, _args) = *func_ty.kind()
205                    && let Some(intrinsic) = tcx.intrinsic(def_id)
206                    && self.fx.cx.intrinsic_call_expects_place_always(intrinsic.name)
207                {
208                    self.locals[local] = LocalKind::Memory;
209                }
210                self.define(local, DefLocation::CallReturn { call, target: *target });
211            }
212
213            PlaceContext::NonUse(_)
214            | PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention)
215            | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
216
217            PlaceContext::NonMutatingUse(
218                NonMutatingUseContext::Copy
219                | NonMutatingUseContext::Move
220                // Inspect covers things like `PtrMetadata` and `Discriminant`
221                // which we can treat similar to `Copy` use for the purpose of
222                // whether we can use SSA variables for things.
223                | NonMutatingUseContext::Inspect,
224            ) => match &mut self.locals[local] {
225                LocalKind::ZST => {}
226                LocalKind::Memory => {}
227                LocalKind::SSA(def) if def.dominates(location, self.dominators) => {}
228                // Reads from uninitialized variables (e.g., in dead code, after
229                // optimizations) require locals to be in (uninitialized) memory.
230                // N.B., there can be uninitialized reads of a local visited after
231                // an assignment to that local, if they happen on disjoint paths.
232                kind @ (LocalKind::Unused | LocalKind::SSA(_)) => {
233                    *kind = LocalKind::Memory;
234                }
235            },
236
237            PlaceContext::MutatingUse(
238                MutatingUseContext::Store
239                | MutatingUseContext::SetDiscriminant
240                | MutatingUseContext::AsmOutput
241                | MutatingUseContext::Borrow
242                | MutatingUseContext::RawBorrow
243                | MutatingUseContext::Projection,
244            )
245            | PlaceContext::NonMutatingUse(
246                NonMutatingUseContext::SharedBorrow
247                | NonMutatingUseContext::FakeBorrow
248                | NonMutatingUseContext::RawBorrow
249                | NonMutatingUseContext::Projection,
250            ) => {
251                self.locals[local] = LocalKind::Memory;
252            }
253
254            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
255                let kind = &mut self.locals[local];
256                if *kind != LocalKind::Memory {
257                    let ty = self.fx.mir.local_decls[local].ty;
258                    let ty = self.fx.monomorphize(ty);
259                    if self.fx.cx.type_needs_drop(ty) {
260                        // Only need the place if we're actually dropping it.
261                        *kind = LocalKind::Memory;
262                    }
263                }
264            }
265
266            PlaceContext::MutatingUse(MutatingUseContext::Yield) => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
267        }
268    }
269
270    fn visit_statement_debuginfo(&mut self, _: &mir::StmtDebugInfo<'tcx>, _: Location) {
271        // Debuginfo does not generate actual code.
272    }
273}
274
275#[derive(#[automatically_derived]
impl ::core::marker::Copy for CleanupKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for CleanupKind {
    #[inline]
    fn clone(&self) -> CleanupKind {
        let _: ::core::clone::AssertParamIsClone<mir::BasicBlock>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for CleanupKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CleanupKind::NotCleanup =>
                ::core::fmt::Formatter::write_str(f, "NotCleanup"),
            CleanupKind::Funclet =>
                ::core::fmt::Formatter::write_str(f, "Funclet"),
            CleanupKind::Internal { funclet: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Internal", "funclet", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for CleanupKind {
    #[inline]
    fn eq(&self, other: &CleanupKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (CleanupKind::Internal { funclet: __self_0 },
                    CleanupKind::Internal { funclet: __arg1_0 }) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CleanupKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<mir::BasicBlock>;
    }
}Eq)]
276pub(crate) enum CleanupKind {
277    NotCleanup,
278    Funclet,
279    Internal { funclet: mir::BasicBlock },
280}
281
282impl CleanupKind {
283    pub(crate) fn funclet_bb(self, for_bb: mir::BasicBlock) -> Option<mir::BasicBlock> {
284        match self {
285            CleanupKind::NotCleanup => None,
286            CleanupKind::Funclet => Some(for_bb),
287            CleanupKind::Internal { funclet } => Some(funclet),
288        }
289    }
290}
291
292/// MSVC requires unwinding code to be split to a tree of *funclets*, where each funclet can only
293/// branch to itself or to its parent. Luckily, the code we generates matches this pattern.
294/// Recover that structure in an analyze pass.
295pub(crate) fn cleanup_kinds(
296    mir: &mir::Body<'_>,
297    nop_landing_pads: &DenseBitSet<mir::BasicBlock>,
298) -> IndexVec<mir::BasicBlock, CleanupKind> {
299    fn discover_masters<'tcx>(
300        result: &mut IndexSlice<mir::BasicBlock, CleanupKind>,
301        mir: &mir::Body<'tcx>,
302        nop_landing_pads: &DenseBitSet<mir::BasicBlock>,
303    ) {
304        for (bb, data) in mir.basic_blocks.iter_enumerated() {
305            match data.terminator().kind {
306                TerminatorKind::Goto { .. }
307                | TerminatorKind::UnwindResume
308                | TerminatorKind::UnwindTerminate(_)
309                | TerminatorKind::Return
310                | TerminatorKind::TailCall { .. }
311                | TerminatorKind::CoroutineDrop
312                | TerminatorKind::Unreachable
313                | TerminatorKind::SwitchInt { .. }
314                | TerminatorKind::Yield { .. }
315                | TerminatorKind::FalseEdge { .. }
316                | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
317                TerminatorKind::Call { unwind, .. }
318                | TerminatorKind::InlineAsm { unwind, .. }
319                | TerminatorKind::Assert { unwind, .. }
320                | TerminatorKind::Drop { unwind, .. } => {
321                    if let mir::UnwindAction::Cleanup(unwind) = unwind
322                        && !nop_landing_pads.contains(unwind)
323                    {
324                        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:324",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(324u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cleanup_kinds: {0:?}/{1:?} registering {2:?} as funclet",
                                                    bb, data, unwind) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
325                            "cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
326                            bb, data, unwind
327                        );
328                        result[unwind] = CleanupKind::Funclet;
329                    }
330                }
331            }
332        }
333    }
334
335    fn propagate<'tcx>(
336        result: &mut IndexSlice<mir::BasicBlock, CleanupKind>,
337        mir: &mir::Body<'tcx>,
338    ) {
339        let mut funclet_succs = IndexVec::from_elem(None, &mir.basic_blocks);
340
341        let mut set_successor = |funclet: mir::BasicBlock, succ| match funclet_succs[funclet] {
342            ref mut s @ None => {
343                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:343",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(343u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("set_successor: updating successor of {0:?} to {1:?}",
                                                    funclet, succ) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("set_successor: updating successor of {:?} to {:?}", funclet, succ);
344                *s = Some(succ);
345            }
346            Some(s) => {
347                if s != succ {
348                    ::rustc_middle::util::bug::span_bug_fmt(mir.span,
    format_args!("funclet {0:?} has 2 parents - {1:?} and {2:?}", funclet, s,
        succ));span_bug!(
349                        mir.span,
350                        "funclet {:?} has 2 parents - {:?} and {:?}",
351                        funclet,
352                        s,
353                        succ
354                    );
355                }
356            }
357        };
358
359        for (bb, data) in traversal::reverse_postorder(mir) {
360            let funclet = match result[bb] {
361                CleanupKind::NotCleanup => continue,
362                CleanupKind::Funclet => bb,
363                CleanupKind::Internal { funclet } => funclet,
364            };
365
366            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:366",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(366u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cleanup_kinds: {0:?}/{1:?}/{2:?} propagating funclet {3:?}",
                                                    bb, data, result[bb], funclet) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
367                "cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}",
368                bb, data, result[bb], funclet
369            );
370
371            for succ in data.terminator().successors() {
372                let kind = result[succ];
373                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:373",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(373u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cleanup_kinds: propagating {0:?} to {1:?}/{2:?}",
                                                    funclet, succ, kind) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind);
374                match kind {
375                    CleanupKind::NotCleanup => {
376                        result[succ] = CleanupKind::Internal { funclet };
377                    }
378                    CleanupKind::Funclet => {
379                        if funclet != succ {
380                            set_successor(funclet, succ);
381                        }
382                    }
383                    CleanupKind::Internal { funclet: succ_funclet } => {
384                        if funclet != succ_funclet {
385                            // `succ` has 2 different funclet going into it, so it must
386                            // be a funclet by itself.
387
388                            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:388",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(388u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("promoting {0:?} to a funclet and updating {1:?}",
                                                    succ, succ_funclet) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(
389                                "promoting {:?} to a funclet and updating {:?}",
390                                succ, succ_funclet
391                            );
392                            result[succ] = CleanupKind::Funclet;
393                            set_successor(succ_funclet, succ);
394                            set_successor(funclet, succ);
395                        }
396                    }
397                }
398            }
399        }
400    }
401
402    let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, &mir.basic_blocks);
403
404    discover_masters(&mut result, mir, &nop_landing_pads);
405    propagate(&mut result, mir);
406    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/mir/analyze.rs:406",
                        "rustc_codegen_ssa::mir::analyze", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/mir/analyze.rs"),
                        ::tracing_core::__macro_support::Option::Some(406u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::mir::analyze"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("cleanup_kinds: result={0:?}",
                                                    result) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("cleanup_kinds: result={:?}", result);
407    result
408}