1use super::{BlockId, InstId, ValueId};
4use smallvec::SmallVec;
5use std::fmt;
6
7#[derive(Clone, Debug)]
9pub struct BasicBlock {
10 pub instructions: Vec<InstId>,
12 pub terminator: Option<Terminator>,
14 pub predecessors: SmallVec<[BlockId; 4]>,
16}
17
18impl BasicBlock {
19 #[must_use]
21 pub fn new() -> Self {
22 Self { instructions: Vec::new(), terminator: None, predecessors: SmallVec::new() }
23 }
24
25 #[must_use]
27 pub const fn is_terminated(&self) -> bool {
28 self.terminator.is_some()
29 }
30
31 #[must_use]
33 pub const fn terminator(&self) -> Option<&Terminator> {
34 self.terminator.as_ref()
35 }
36}
37
38impl Default for BasicBlock {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44#[derive(Clone, Debug, PartialEq)]
46pub enum Terminator {
47 Jump(BlockId),
49 Branch {
51 condition: ValueId,
53 then_block: BlockId,
55 else_block: BlockId,
57 },
58 Switch {
60 value: ValueId,
62 default: BlockId,
64 cases: Vec<(ValueId, BlockId)>,
66 },
67 Return {
69 values: SmallVec<[ValueId; 2]>,
71 },
72 Revert {
74 offset: ValueId,
76 size: ValueId,
78 },
79 ReturnData {
82 offset: ValueId,
84 size: ValueId,
86 },
87 Stop,
89 SelfDestruct {
91 recipient: ValueId,
93 },
94 Invalid,
96}
97
98impl Terminator {
99 #[must_use]
101 pub fn successors(&self) -> SmallVec<[BlockId; 2]> {
102 match self {
103 Self::Jump(target) => smallvec::smallvec![*target],
104 Self::Branch { then_block, else_block, .. } => {
105 smallvec::smallvec![*then_block, *else_block]
106 }
107 Self::Switch { default, cases, .. } => {
108 let mut succs = SmallVec::with_capacity(cases.len() + 1);
109 succs.push(*default);
110 for (_, block) in cases {
111 succs.push(*block);
112 }
113 succs
114 }
115 Self::Return { .. }
116 | Self::Revert { .. }
117 | Self::ReturnData { .. }
118 | Self::Stop
119 | Self::SelfDestruct { .. }
120 | Self::Invalid => SmallVec::new(),
121 }
122 }
123
124 #[must_use]
126 pub const fn mnemonic(&self) -> &'static str {
127 match self {
128 Self::Jump(_) => "jump",
129 Self::Branch { .. } => "branch",
130 Self::Switch { .. } => "switch",
131 Self::Return { .. } => "return",
132 Self::Revert { .. } => "revert",
133 Self::ReturnData { .. } => "returndata",
134 Self::Stop => "stop",
135 Self::SelfDestruct { .. } => "selfdestruct",
136 Self::Invalid => "invalid",
137 }
138 }
139
140 #[must_use]
143 pub fn operands(&self) -> SmallVec<[ValueId; 4]> {
144 let mut out = SmallVec::new();
145 match self {
146 Self::Jump(_) => {}
147 Self::Branch { condition, .. } => out.push(*condition),
148 Self::Switch { value, cases, .. } => {
149 out.push(*value);
150 for (case_val, _) in cases {
151 out.push(*case_val);
152 }
153 }
154 Self::Return { values } => out.extend(values.iter().copied()),
155 Self::Revert { offset, size } | Self::ReturnData { offset, size } => {
156 out.push(*offset);
157 out.push(*size);
158 }
159 Self::Stop | Self::Invalid => {}
160 Self::SelfDestruct { recipient } => out.push(*recipient),
161 }
162 out
163 }
164}
165
166impl fmt::Display for Terminator {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 match self {
169 Self::Jump(target) => write!(f, "jump bb{}", target.index()),
170 Self::Branch { condition, then_block, else_block } => {
171 write!(
172 f,
173 "branch v{}, bb{}, bb{}",
174 condition.index(),
175 then_block.index(),
176 else_block.index()
177 )
178 }
179 Self::Switch { value, default, cases } => {
180 write!(f, "switch v{}, default bb{}", value.index(), default.index())?;
181 for (val, block) in cases {
182 write!(f, ", v{} => bb{}", val.index(), block.index())?;
183 }
184 Ok(())
185 }
186 Self::Return { values } => {
187 write!(f, "return")?;
188 for (i, v) in values.iter().enumerate() {
189 if i > 0 {
190 write!(f, ",")?;
191 }
192 write!(f, " v{}", v.index())?;
193 }
194 Ok(())
195 }
196 Self::Revert { offset, size } => {
197 write!(f, "revert v{}, v{}", offset.index(), size.index())
198 }
199 Self::ReturnData { offset, size } => {
200 write!(f, "returndata v{}, v{}", offset.index(), size.index())
201 }
202 Self::Stop => write!(f, "stop"),
203 Self::SelfDestruct { recipient } => {
204 write!(f, "selfdestruct v{}", recipient.index())
205 }
206 Self::Invalid => write!(f, "invalid"),
207 }
208 }
209}