1use fe_analyzer::namespace::items::ContractId;
2use num_bigint::BigInt;
3
4use crate::ir::{
5 body_cursor::{BodyCursor, CursorLocation},
6 inst::{BinOp, Inst, InstKind, UnOp},
7 value::{AssignableValue, Local},
8 BasicBlock, BasicBlockId, FunctionBody, FunctionId, InstId, SourceInfo, TypeId,
9};
10
11use super::{
12 inst::{CallType, CastKind, SwitchTable, YulIntrinsicOp},
13 ConstantId, Value, ValueId,
14};
15
16#[derive(Debug)]
17pub struct BodyBuilder {
18 pub body: FunctionBody,
19 loc: CursorLocation,
20}
21
22macro_rules! impl_unary_inst {
23 ($name:ident, $code:path) => {
24 pub fn $name(&mut self, value: ValueId, source: SourceInfo) -> InstId {
25 let inst = Inst::unary($code, value, source);
26 self.insert_inst(inst)
27 }
28 };
29}
30
31macro_rules! impl_binary_inst {
32 ($name:ident, $code:path) => {
33 pub fn $name(&mut self, lhs: ValueId, rhs: ValueId, source: SourceInfo) -> InstId {
34 let inst = Inst::binary($code, lhs, rhs, source);
35 self.insert_inst(inst)
36 }
37 };
38}
39
40impl BodyBuilder {
41 pub fn new(fid: FunctionId, source: SourceInfo) -> Self {
42 let body = FunctionBody::new(fid, source);
43 let entry_block = body.order.entry();
44 Self {
45 body,
46 loc: CursorLocation::BlockTop(entry_block),
47 }
48 }
49
50 pub fn build(self) -> FunctionBody {
51 self.body
52 }
53
54 pub fn func_id(&self) -> FunctionId {
55 self.body.fid
56 }
57
58 pub fn make_block(&mut self) -> BasicBlockId {
59 let block = BasicBlock {};
60 let block_id = self.body.store.store_block(block);
61 self.body.order.append_block(block_id);
62 block_id
63 }
64
65 pub fn make_value(&mut self, value: impl Into<Value>) -> ValueId {
66 self.body.store.store_value(value.into())
67 }
68
69 pub fn map_result(&mut self, inst: InstId, result: AssignableValue) {
70 self.body.store.map_result(inst, result)
71 }
72
73 pub fn inst_result(&mut self, inst: InstId) -> Option<&AssignableValue> {
74 self.body.store.inst_result(inst)
75 }
76
77 pub fn move_to_block(&mut self, block: BasicBlockId) {
78 self.loc = CursorLocation::BlockBottom(block)
79 }
80
81 pub fn move_to_block_top(&mut self, block: BasicBlockId) {
82 self.loc = CursorLocation::BlockTop(block)
83 }
84
85 pub fn make_unit(&mut self, unit_ty: TypeId) -> ValueId {
86 self.body.store.store_value(Value::Unit { ty: unit_ty })
87 }
88
89 pub fn make_imm(&mut self, imm: BigInt, ty: TypeId) -> ValueId {
90 self.body.store.store_value(Value::Immediate { imm, ty })
91 }
92
93 pub fn make_imm_from_bool(&mut self, imm: bool, ty: TypeId) -> ValueId {
94 if imm {
95 self.make_imm(1u8.into(), ty)
96 } else {
97 self.make_imm(0u8.into(), ty)
98 }
99 }
100
101 pub fn make_constant(&mut self, constant: ConstantId, ty: TypeId) -> ValueId {
102 self.body
103 .store
104 .store_value(Value::Constant { constant, ty })
105 }
106
107 pub fn declare(&mut self, local: Local) -> ValueId {
108 let source = local.source.clone();
109 let local_id = self.body.store.store_value(Value::Local(local));
110
111 let kind = InstKind::Declare { local: local_id };
112 let inst = Inst::new(kind, source);
113 self.insert_inst(inst);
114 local_id
115 }
116
117 pub fn store_func_arg(&mut self, local: Local) -> ValueId {
118 self.body.store.store_value(Value::Local(local))
119 }
120
121 impl_unary_inst!(not, UnOp::Not);
122 impl_unary_inst!(neg, UnOp::Neg);
123 impl_unary_inst!(inv, UnOp::Inv);
124
125 impl_binary_inst!(add, BinOp::Add);
126 impl_binary_inst!(sub, BinOp::Sub);
127 impl_binary_inst!(mul, BinOp::Mul);
128 impl_binary_inst!(div, BinOp::Div);
129 impl_binary_inst!(modulo, BinOp::Mod);
130 impl_binary_inst!(pow, BinOp::Pow);
131 impl_binary_inst!(shl, BinOp::Shl);
132 impl_binary_inst!(shr, BinOp::Shr);
133 impl_binary_inst!(bit_or, BinOp::BitOr);
134 impl_binary_inst!(bit_xor, BinOp::BitXor);
135 impl_binary_inst!(bit_and, BinOp::BitAnd);
136 impl_binary_inst!(logical_and, BinOp::LogicalAnd);
137 impl_binary_inst!(logical_or, BinOp::LogicalOr);
138 impl_binary_inst!(eq, BinOp::Eq);
139 impl_binary_inst!(ne, BinOp::Ne);
140 impl_binary_inst!(ge, BinOp::Ge);
141 impl_binary_inst!(gt, BinOp::Gt);
142 impl_binary_inst!(le, BinOp::Le);
143 impl_binary_inst!(lt, BinOp::Lt);
144
145 pub fn primitive_cast(
146 &mut self,
147 value: ValueId,
148 result_ty: TypeId,
149 source: SourceInfo,
150 ) -> InstId {
151 let kind = InstKind::Cast {
152 kind: CastKind::Primitive,
153 value,
154 to: result_ty,
155 };
156 let inst = Inst::new(kind, source);
157 self.insert_inst(inst)
158 }
159
160 pub fn untag_cast(&mut self, value: ValueId, result_ty: TypeId, source: SourceInfo) -> InstId {
161 let kind = InstKind::Cast {
162 kind: CastKind::Untag,
163 value,
164 to: result_ty,
165 };
166 let inst = Inst::new(kind, source);
167 self.insert_inst(inst)
168 }
169
170 pub fn aggregate_construct(
171 &mut self,
172 ty: TypeId,
173 args: Vec<ValueId>,
174 source: SourceInfo,
175 ) -> InstId {
176 let kind = InstKind::AggregateConstruct { ty, args };
177 let inst = Inst::new(kind, source);
178 self.insert_inst(inst)
179 }
180
181 pub fn bind(&mut self, src: ValueId, source: SourceInfo) -> InstId {
182 let kind = InstKind::Bind { src };
183 let inst = Inst::new(kind, source);
184 self.insert_inst(inst)
185 }
186
187 pub fn mem_copy(&mut self, src: ValueId, source: SourceInfo) -> InstId {
188 let kind = InstKind::MemCopy { src };
189 let inst = Inst::new(kind, source);
190 self.insert_inst(inst)
191 }
192
193 pub fn load(&mut self, src: ValueId, source: SourceInfo) -> InstId {
194 let kind = InstKind::Load { src };
195 let inst = Inst::new(kind, source);
196 self.insert_inst(inst)
197 }
198
199 pub fn aggregate_access(
200 &mut self,
201 value: ValueId,
202 indices: Vec<ValueId>,
203 source: SourceInfo,
204 ) -> InstId {
205 let kind = InstKind::AggregateAccess { value, indices };
206 let inst = Inst::new(kind, source);
207 self.insert_inst(inst)
208 }
209
210 pub fn map_access(&mut self, value: ValueId, key: ValueId, source: SourceInfo) -> InstId {
211 let kind = InstKind::MapAccess { value, key };
212 let inst = Inst::new(kind, source);
213 self.insert_inst(inst)
214 }
215
216 pub fn call(
217 &mut self,
218 func: FunctionId,
219 args: Vec<ValueId>,
220 call_type: CallType,
221 source: SourceInfo,
222 ) -> InstId {
223 let kind = InstKind::Call {
224 func,
225 args,
226 call_type,
227 };
228 let inst = Inst::new(kind, source);
229 self.insert_inst(inst)
230 }
231
232 pub fn keccak256(&mut self, arg: ValueId, source: SourceInfo) -> InstId {
233 let kind = InstKind::Keccak256 { arg };
234 let inst = Inst::new(kind, source);
235 self.insert_inst(inst)
236 }
237
238 pub fn abi_encode(&mut self, arg: ValueId, source: SourceInfo) -> InstId {
239 let kind = InstKind::AbiEncode { arg };
240 let inst = Inst::new(kind, source);
241 self.insert_inst(inst)
242 }
243
244 pub fn create(&mut self, value: ValueId, contract: ContractId, source: SourceInfo) -> InstId {
245 let kind = InstKind::Create { value, contract };
246 let inst = Inst::new(kind, source);
247 self.insert_inst(inst)
248 }
249
250 pub fn create2(
251 &mut self,
252 value: ValueId,
253 salt: ValueId,
254 contract: ContractId,
255 source: SourceInfo,
256 ) -> InstId {
257 let kind = InstKind::Create2 {
258 value,
259 salt,
260 contract,
261 };
262 let inst = Inst::new(kind, source);
263 self.insert_inst(inst)
264 }
265
266 pub fn yul_intrinsic(
267 &mut self,
268 op: YulIntrinsicOp,
269 args: Vec<ValueId>,
270 source: SourceInfo,
271 ) -> InstId {
272 let inst = Inst::intrinsic(op, args, source);
273 self.insert_inst(inst)
274 }
275
276 pub fn jump(&mut self, dest: BasicBlockId, source: SourceInfo) -> InstId {
277 let kind = InstKind::Jump { dest };
278 let inst = Inst::new(kind, source);
279 self.insert_inst(inst)
280 }
281
282 pub fn branch(
283 &mut self,
284 cond: ValueId,
285 then: BasicBlockId,
286 else_: BasicBlockId,
287 source: SourceInfo,
288 ) -> InstId {
289 let kind = InstKind::Branch { cond, then, else_ };
290 let inst = Inst::new(kind, source);
291 self.insert_inst(inst)
292 }
293
294 pub fn switch(
295 &mut self,
296 disc: ValueId,
297 table: SwitchTable,
298 default: Option<BasicBlockId>,
299 source: SourceInfo,
300 ) -> InstId {
301 let kind = InstKind::Switch {
302 disc,
303 table,
304 default,
305 };
306 let inst = Inst::new(kind, source);
307 self.insert_inst(inst)
308 }
309
310 pub fn revert(&mut self, arg: Option<ValueId>, source: SourceInfo) -> InstId {
311 let kind = InstKind::Revert { arg };
312 let inst = Inst::new(kind, source);
313 self.insert_inst(inst)
314 }
315
316 pub fn emit(&mut self, arg: ValueId, source: SourceInfo) -> InstId {
317 let kind = InstKind::Emit { arg };
318 let inst = Inst::new(kind, source);
319 self.insert_inst(inst)
320 }
321
322 pub fn ret(&mut self, arg: ValueId, source: SourceInfo) -> InstId {
323 let kind = InstKind::Return { arg: arg.into() };
324 let inst = Inst::new(kind, source);
325 self.insert_inst(inst)
326 }
327
328 pub fn nop(&mut self, source: SourceInfo) -> InstId {
329 let kind = InstKind::Nop;
330 let inst = Inst::new(kind, source);
331 self.insert_inst(inst)
332 }
333
334 pub fn value_ty(&mut self, value: ValueId) -> TypeId {
335 self.body.store.value_ty(value)
336 }
337
338 pub fn value_data(&mut self, value: ValueId) -> &Value {
339 self.body.store.value_data(value)
340 }
341
342 pub fn is_block_terminated(&mut self, block: BasicBlockId) -> bool {
344 self.body.order.is_terminated(&self.body.store, block)
345 }
346
347 pub fn is_current_block_terminated(&mut self) -> bool {
348 let current_block = self.current_block();
349 self.is_block_terminated(current_block)
350 }
351
352 pub fn current_block(&mut self) -> BasicBlockId {
353 self.cursor().expect_block()
354 }
355
356 pub fn remove_inst(&mut self, inst: InstId) {
357 let mut cursor = BodyCursor::new(&mut self.body, CursorLocation::Inst(inst));
358 if self.loc == cursor.loc() {
359 self.loc = cursor.prev_loc();
360 }
361 cursor.remove_inst();
362 }
363
364 pub fn inst_data(&self, inst: InstId) -> &Inst {
365 self.body.store.inst_data(inst)
366 }
367
368 fn insert_inst(&mut self, inst: Inst) -> InstId {
369 let mut cursor = self.cursor();
370 let inst_id = cursor.store_and_insert_inst(inst);
371
372 self.loc = CursorLocation::Inst(inst_id);
374
375 inst_id
376 }
377
378 fn cursor(&mut self) -> BodyCursor {
379 BodyCursor::new(&mut self.body, self.loc)
380 }
381}