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}