Skip to main content

rustc_mir_build/builder/
cfg.rs

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