Skip to main content

llvm_ir/
basic_block.rs

1//! Basic block: a sequence of non-terminating instructions ending with a terminator.
2
3use crate::context::InstrId;
4
5/// A basic block within a function.
6///
7/// The block owns a list of non-terminator `InstrId`s (the body) and an
8/// optional terminator `InstrId`. All `InstrId`s index into the owning
9/// `Function`'s flat `instructions` pool.
10#[derive(Clone, Debug)]
11pub struct BasicBlock {
12    /// Public API for `name`.
13    pub name: String,
14    /// Non-terminator instructions, in order.
15    pub body: Vec<InstrId>,
16    /// The terminator instruction, if present.
17    pub terminator: Option<InstrId>,
18}
19
20impl BasicBlock {
21    /// Public API for `new`.
22    pub fn new(name: impl Into<String>) -> Self {
23        BasicBlock {
24            name: name.into(),
25            body: Vec::new(),
26            terminator: None,
27        }
28    }
29
30    /// Append a non-terminator instruction.
31    pub fn append_instr(&mut self, id: InstrId) {
32        self.body.push(id);
33    }
34
35    /// Set the terminator instruction (replaces any existing one).
36    pub fn set_terminator(&mut self, id: InstrId) {
37        self.terminator = Some(id);
38    }
39
40    /// True if the block has a terminator.
41    pub fn is_complete(&self) -> bool {
42        self.terminator.is_some()
43    }
44
45    /// Iterate over all instruction ids in order (body + terminator).
46    pub fn instrs(&self) -> impl Iterator<Item = InstrId> + '_ {
47        self.body.iter().copied().chain(self.terminator.into_iter())
48    }
49
50    /// Number of instructions (body + optional terminator).
51    pub fn len(&self) -> usize {
52        self.body.len() + if self.terminator.is_some() { 1 } else { 0 }
53    }
54
55    /// Public API for `is_empty`.
56    pub fn is_empty(&self) -> bool {
57        self.len() == 0
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn basic_block_new() {
67        let bb = BasicBlock::new("entry");
68        assert_eq!(bb.name, "entry");
69        assert!(bb.body.is_empty());
70        assert!(bb.terminator.is_none());
71        assert!(!bb.is_complete());
72    }
73
74    #[test]
75    fn append_and_terminate() {
76        let mut bb = BasicBlock::new("bb0");
77        bb.append_instr(InstrId(0));
78        bb.append_instr(InstrId(1));
79        bb.set_terminator(InstrId(2));
80        assert!(bb.is_complete());
81        assert_eq!(bb.len(), 3);
82        let ids: Vec<_> = bb.instrs().collect();
83        assert_eq!(ids, vec![InstrId(0), InstrId(1), InstrId(2)]);
84    }
85}