Skip to main content

thalir_core/
block.rs

1use crate::instructions::Instruction;
2use crate::types::Type;
3use crate::values::{SourceLocation, Value};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
8pub struct BlockId(pub u32);
9
10impl std::fmt::Display for BlockId {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        write!(f, "block{}", self.0)
13    }
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct BasicBlock {
18    pub id: BlockId,
19    pub params: Vec<BlockParam>,
20    pub instructions: Vec<Instruction>,
21    pub terminator: Terminator,
22    pub metadata: BlockMetadata,
23}
24
25impl BasicBlock {
26    pub fn new(id: BlockId) -> Self {
27        Self {
28            id,
29            params: Vec::new(),
30            instructions: Vec::new(),
31            terminator: Terminator::Invalid,
32            metadata: BlockMetadata::default(),
33        }
34    }
35
36    pub fn add_param(&mut self, param: BlockParam) {
37        self.params.push(param);
38    }
39
40    pub fn add_instruction(&mut self, inst: Instruction) {
41        self.instructions.push(inst);
42    }
43
44    pub fn set_terminator(&mut self, term: Terminator) {
45        self.terminator = term;
46    }
47
48    pub fn is_terminated(&self) -> bool {
49        !matches!(self.terminator, Terminator::Invalid)
50    }
51
52    pub fn predecessors(&self) -> Vec<BlockId> {
53        Vec::new()
54    }
55
56    pub fn successors(&self) -> Vec<BlockId> {
57        match &self.terminator {
58            Terminator::Jump(target, _) => vec![*target],
59            Terminator::Branch {
60                then_block,
61                else_block,
62                ..
63            } => {
64                vec![*then_block, *else_block]
65            }
66            Terminator::Switch { default, cases, .. } => {
67                let mut succs = vec![*default];
68                succs.extend(cases.iter().map(|(_, block)| *block));
69                succs
70            }
71            _ => Vec::new(),
72        }
73    }
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct BlockParam {
78    pub name: String,
79    pub param_type: Type,
80}
81
82impl BlockParam {
83    pub fn new(name: impl Into<String>, param_type: Type) -> Self {
84        Self {
85            name: name.into(),
86            param_type,
87        }
88    }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub enum Terminator {
93    Jump(BlockId, Vec<Value>),
94    Branch {
95        condition: Value,
96        then_block: BlockId,
97        then_args: Vec<Value>,
98        else_block: BlockId,
99        else_args: Vec<Value>,
100    },
101
102    Switch {
103        value: Value,
104        default: BlockId,
105        cases: Vec<(Value, BlockId)>,
106    },
107
108    Return(Option<Value>),
109
110    Revert(String),
111
112    Panic(String),
113
114    Invalid,
115}
116
117impl Terminator {
118    pub fn successors(&self) -> Vec<BlockId> {
119        match self {
120            Terminator::Jump(target, _) => vec![*target],
121            Terminator::Branch {
122                then_block,
123                else_block,
124                ..
125            } => vec![*then_block, *else_block],
126            Terminator::Switch { default, cases, .. } => {
127                let mut blocks = vec![*default];
128                blocks.extend(cases.iter().map(|(_, block)| *block));
129                blocks
130            }
131            Terminator::Return(_)
132            | Terminator::Revert(_)
133            | Terminator::Panic(_)
134            | Terminator::Invalid => vec![],
135        }
136    }
137
138    pub fn is_return(&self) -> bool {
139        matches!(self, Terminator::Return(_))
140    }
141
142    pub fn is_revert(&self) -> bool {
143        matches!(self, Terminator::Revert(_) | Terminator::Panic(_))
144    }
145}
146
147#[derive(Debug, Clone, Default, Serialize, Deserialize)]
148pub struct BlockMetadata {
149    pub is_loop_header: bool,
150    pub is_loop_exit: bool,
151    pub loop_depth: u32,
152    pub predecessors: Vec<BlockId>,
153    pub dominators: Vec<BlockId>,
154    pub is_reachable: bool,
155    pub instruction_locations: HashMap<usize, SourceLocation>,
156}
157
158impl BlockMetadata {
159    pub fn get_location(&self, index: usize) -> Option<&SourceLocation> {
160        self.instruction_locations.get(&index)
161    }
162
163    pub fn set_location(&mut self, index: usize, location: SourceLocation) {
164        self.instruction_locations.insert(index, location);
165    }
166}