rustc_mir_build/builder/
cfg.rs

1//! Routines for manipulating the control-flow graph.
2
3use rustc_middle::mir::*;
4use rustc_middle::ty::TyCtxt;
5use tracing::debug;
6
7use crate::builder::CFG;
8
9impl<'tcx> CFG<'tcx> {
10    pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
11        &self.basic_blocks[blk]
12    }
13
14    pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
15        &mut self.basic_blocks[blk]
16    }
17
18    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
19    // it as #[inline(never)] to keep rustc's stack use in check.
20    #[inline(never)]
21    pub(crate) fn start_new_block(&mut self) -> BasicBlock {
22        self.basic_blocks.push(BasicBlockData::new(None, false))
23    }
24
25    pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
26        let bb = self.start_new_block();
27        self.block_data_mut(bb).is_cleanup = true;
28        bb
29    }
30
31    pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
32        debug!("push({:?}, {:?})", block, statement);
33        self.block_data_mut(block).statements.push(statement);
34    }
35
36    pub(crate) fn push_assign(
37        &mut self,
38        block: BasicBlock,
39        source_info: SourceInfo,
40        place: Place<'tcx>,
41        rvalue: Rvalue<'tcx>,
42    ) {
43        self.push(
44            block,
45            Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) },
46        );
47    }
48
49    pub(crate) fn push_assign_constant(
50        &mut self,
51        block: BasicBlock,
52        source_info: SourceInfo,
53        temp: Place<'tcx>,
54        constant: ConstOperand<'tcx>,
55    ) {
56        self.push_assign(
57            block,
58            source_info,
59            temp,
60            Rvalue::Use(Operand::Constant(Box::new(constant))),
61        );
62    }
63
64    pub(crate) fn push_assign_unit(
65        &mut self,
66        block: BasicBlock,
67        source_info: SourceInfo,
68        place: Place<'tcx>,
69        tcx: TyCtxt<'tcx>,
70    ) {
71        self.push_assign(
72            block,
73            source_info,
74            place,
75            Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
76                span: source_info.span,
77                user_ty: None,
78                const_: Const::zero_sized(tcx.types.unit),
79            }))),
80        );
81    }
82
83    pub(crate) fn push_fake_read(
84        &mut self,
85        block: BasicBlock,
86        source_info: SourceInfo,
87        cause: FakeReadCause,
88        place: Place<'tcx>,
89    ) {
90        let kind = StatementKind::FakeRead(Box::new((cause, place)));
91        let stmt = Statement { source_info, kind };
92        self.push(block, stmt);
93    }
94
95    pub(crate) fn push_place_mention(
96        &mut self,
97        block: BasicBlock,
98        source_info: SourceInfo,
99        place: Place<'tcx>,
100    ) {
101        let kind = StatementKind::PlaceMention(Box::new(place));
102        let stmt = Statement { source_info, kind };
103        self.push(block, stmt);
104    }
105
106    /// Adds a dummy statement whose only role is to associate a span with its
107    /// enclosing block for the purposes of coverage instrumentation.
108    ///
109    /// This results in more accurate coverage reports for certain kinds of
110    /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
111    pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
112        let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
113        let stmt = Statement { source_info, kind };
114        self.push(block, stmt);
115    }
116
117    pub(crate) fn terminate(
118        &mut self,
119        block: BasicBlock,
120        source_info: SourceInfo,
121        kind: TerminatorKind<'tcx>,
122    ) {
123        debug!("terminating block {:?} <- {:?}", block, kind);
124        debug_assert!(
125            self.block_data(block).terminator.is_none(),
126            "terminate: block {:?}={:?} already has a terminator set",
127            block,
128            self.block_data(block)
129        );
130        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
131    }
132
133    /// In the `origin` block, push a `goto -> target` terminator.
134    pub(crate) fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
135        self.terminate(origin, source_info, TerminatorKind::Goto { target })
136    }
137}