Skip to main content

rustc_mir_build/builder/
cfg.rs

1//! Routines for manipulating the control-flow graph.
2
3use rustc_attr_ir::UnrollAttr;
4use rustc_data_structures::thin_vec::ThinVec;
5use rustc_middle::mir::*;
6use rustc_middle::ty::TyCtxt;
7use tracing::debug;
8
9use crate::builder::CFG;
10
11impl<'tcx> CFG<'tcx> {
12    pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
13        &self.basic_blocks[blk]
14    }
15
16    pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
17        &mut self.basic_blocks[blk]
18    }
19
20    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
21    // it as #[inline(never)] to keep rustc's stack use in check.
22    #[inline(never)]
23    pub(crate) fn start_new_block(&mut self) -> BasicBlock {
24        self.basic_blocks.push(BasicBlockData::new(None, false))
25    }
26
27    pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
28        let bb = self.start_new_block();
29        self.block_data_mut(bb).is_cleanup = true;
30        bb
31    }
32
33    pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
34        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/92ffebeceaa0a071066f233873c2438e73d70fe7/compiler/rustc_mir_build/src/builder/cfg.rs:34",
                        "rustc_mir_build::builder::cfg", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/92ffebeceaa0a071066f233873c2438e73d70fe7/compiler/rustc_mir_build/src/builder/cfg.rs"),
                        ::tracing_core::__macro_support::Option::Some(34u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::builder::cfg"),
                        ::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!("push({0:?}, {1:?})",
                                                    block, statement) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("push({:?}, {:?})", block, statement);
35        self.block_data_mut(block).statements.push(statement);
36    }
37
38    pub(crate) fn push_assign(
39        &mut self,
40        block: BasicBlock,
41        source_info: SourceInfo,
42        place: Place<'tcx>,
43        rvalue: Rvalue<'tcx>,
44    ) {
45        self.push(
46            block,
47            Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))),
48        );
49    }
50
51    pub(crate) fn push_assign_constant(
52        &mut self,
53        block: BasicBlock,
54        source_info: SourceInfo,
55        temp: Place<'tcx>,
56        constant: ConstOperand<'tcx>,
57    ) {
58        self.push_assign(
59            block,
60            source_info,
61            temp,
62            Rvalue::Use(Operand::Constant(Box::new(constant)), WithRetag::Yes),
63        );
64    }
65
66    pub(crate) fn push_assign_unit(
67        &mut self,
68        block: BasicBlock,
69        source_info: SourceInfo,
70        place: Place<'tcx>,
71        tcx: TyCtxt<'tcx>,
72    ) {
73        self.push_assign(
74            block,
75            source_info,
76            place,
77            Rvalue::Use(
78                Operand::Constant(Box::new(ConstOperand {
79                    span: source_info.span,
80                    user_ty: None,
81                    const_: Const::zero_sized(tcx.types.unit),
82                })),
83                WithRetag::Yes,
84            ),
85        );
86    }
87
88    pub(crate) fn push_fake_read(
89        &mut self,
90        block: BasicBlock,
91        source_info: SourceInfo,
92        cause: FakeReadCause,
93        place: Place<'tcx>,
94    ) {
95        let kind = StatementKind::FakeRead(Box::new((cause, place)));
96        let stmt = Statement::new(source_info, kind);
97        self.push(block, stmt);
98    }
99
100    pub(crate) fn push_place_mention(
101        &mut self,
102        block: BasicBlock,
103        source_info: SourceInfo,
104        place: Place<'tcx>,
105    ) {
106        let kind = StatementKind::PlaceMention(Box::new(place));
107        let stmt = Statement::new(source_info, kind);
108        self.push(block, stmt);
109    }
110
111    pub(crate) fn terminate(
112        &mut self,
113        block: BasicBlock,
114        source_info: SourceInfo,
115        kind: TerminatorKind<'tcx>,
116    ) -> &mut Terminator<'tcx> {
117        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/92ffebeceaa0a071066f233873c2438e73d70fe7/compiler/rustc_mir_build/src/builder/cfg.rs:117",
                        "rustc_mir_build::builder::cfg", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/92ffebeceaa0a071066f233873c2438e73d70fe7/compiler/rustc_mir_build/src/builder/cfg.rs"),
                        ::tracing_core::__macro_support::Option::Some(117u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::builder::cfg"),
                        ::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!("terminating block {0:?} <- {1:?}",
                                                    block, kind) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("terminating block {:?} <- {:?}", block, kind);
118        if true {
    if !self.block_data(block).terminator.is_none() {
        {
            ::core::panicking::panic_fmt(format_args!("terminate: block {0:?}={1:?} already has a terminator set",
                    block, self.block_data(block)));
        }
    };
};debug_assert!(
119            self.block_data(block).terminator.is_none(),
120            "terminate: block {:?}={:?} already has a terminator set",
121            block,
122            self.block_data(block)
123        );
124        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
125        self.block_data_mut(block).terminator.as_mut().unwrap()
126    }
127
128    /// In the `origin` block, push a `goto -> target` terminator.
129    pub(crate) fn goto(
130        &mut self,
131        origin: BasicBlock,
132        source_info: SourceInfo,
133        target: BasicBlock,
134    ) -> &mut Terminator<'tcx> {
135        self.goto_with_hints(origin, source_info, target, ThinVec::new())
136    }
137
138    #[inline(always)]
139    pub(crate) fn goto_with_hints(
140        &mut self,
141        origin: BasicBlock,
142        source_info: SourceInfo,
143        target: BasicBlock,
144        loop_hint_attrs: ThinVec<UnrollAttr>,
145    ) -> &mut Terminator<'tcx> {
146        self.terminate(origin, source_info, TerminatorKind::Goto { target, loop_hint_attrs })
147    }
148}