1use rustc_hash::FxHashMap;
11use sway_types::Ident;
12
13use crate::{
14 asm::{AsmArg, AsmBlock},
15 block::Block,
16 context::Context,
17 function::Function,
18 irtype::Type,
19 pretty::DebugWithContext,
20 value::{Value, ValueDatum},
21 variable::LocalVar,
22 AsmInstruction, ConstantContent, GlobalVar, Module,
23};
24
25#[derive(Debug, Clone, DebugWithContext)]
26pub struct BranchToWithArgs {
27 pub block: Block,
28 pub args: Vec<Value>,
29}
30
31#[derive(Debug, Clone, DebugWithContext)]
32pub struct Instruction {
33 pub parent: Block,
34 pub op: InstOp,
35}
36
37impl Instruction {
38 pub fn get_type(&self, context: &Context) -> Option<Type> {
39 self.op.get_type(context)
40 }
41 pub fn replace_values(&mut self, replace_map: &FxHashMap<Value, Value>) {
43 self.op.replace_values(replace_map)
44 }
45}
46
47#[derive(Debug, Clone, DebugWithContext)]
48pub enum InstOp {
49 AsmBlock(AsmBlock, Vec<AsmArg>),
51 UnaryOp { op: UnaryOpKind, arg: Value },
53 BinaryOp {
55 op: BinaryOpKind,
56 arg1: Value,
57 arg2: Value,
58 },
59 BitCast(Value, Type),
61 Branch(BranchToWithArgs),
63 Call(Function, Vec<Value>),
65 CastPtr(Value, Type),
67 Cmp(Predicate, Value, Value),
69 ConditionalBranch {
71 cond_value: Value,
72 true_block: BranchToWithArgs,
73 false_block: BranchToWithArgs,
74 },
75 ContractCall {
77 return_type: Type,
78 name: Option<String>,
79 params: Value,
80 coins: Value,
81 asset_id: Value,
82 gas: Value,
83 },
84 FuelVm(FuelVmInstruction),
86 GetLocal(LocalVar),
88 GetGlobal(GlobalVar),
90 GetConfig(Module, String),
92 GetElemPtr {
94 base: Value,
95 elem_ptr_ty: Type,
96 indices: Vec<Value>,
97 },
98 IntToPtr(Value, Type),
100 Load(Value),
102 MemCopyBytes {
104 dst_val_ptr: Value,
105 src_val_ptr: Value,
106 byte_len: u64,
107 },
108 MemCopyVal {
110 dst_val_ptr: Value,
111 src_val_ptr: Value,
112 },
113 Nop,
115 PtrToInt(Value, Type),
117 Ret(Value, Type),
119 Store {
121 dst_val_ptr: Value,
122 stored_val: Value,
123 },
124}
125
126#[derive(Debug, Clone, DebugWithContext)]
127pub enum FuelVmInstruction {
128 Gtf {
129 index: Value,
130 tx_field_id: u64,
131 },
132 Log {
134 log_val: Value,
135 log_ty: Type,
136 log_id: Value,
137 },
138 ReadRegister(Register),
140 Revert(Value),
142 Smo {
147 recipient: Value,
148 message: Value,
149 message_size: Value,
150 coins: Value,
151 },
152 StateClear {
154 key: Value,
155 number_of_slots: Value,
156 },
157 StateLoadQuadWord {
160 load_val: Value,
161 key: Value,
162 number_of_slots: Value,
163 },
164 StateLoadWord(Value),
166 StateStoreQuadWord {
169 stored_val: Value,
170 key: Value,
171 number_of_slots: Value,
172 },
173 StateStoreWord {
176 stored_val: Value,
177 key: Value,
178 },
179 WideUnaryOp {
180 op: UnaryOpKind,
181 result: Value,
182 arg: Value,
183 },
184 WideBinaryOp {
185 op: BinaryOpKind,
186 result: Value,
187 arg1: Value,
188 arg2: Value,
189 },
190 WideModularOp {
191 op: BinaryOpKind,
192 result: Value,
193 arg1: Value,
194 arg2: Value,
195 arg3: Value,
196 },
197 WideCmpOp {
198 op: Predicate,
199 arg1: Value,
200 arg2: Value,
201 },
202 JmpMem,
203 Retd {
204 ptr: Value,
205 len: Value,
206 },
207}
208
209#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
211pub enum Predicate {
212 Equal,
213 LessThan,
214 GreaterThan,
215}
216
217#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
218pub enum UnaryOpKind {
219 Not,
220}
221
222#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
223pub enum BinaryOpKind {
224 Add,
225 Sub,
226 Mul,
227 Div,
228 And,
229 Or,
230 Xor,
231 Mod,
232 Rsh,
233 Lsh,
234}
235
236#[derive(Debug, Clone, Copy, Hash)]
238pub enum Register {
239 Of,
241 Pc,
243 Ssp,
245 Sp,
247 Fp,
249 Hp,
251 Error,
253 Ggas,
255 Cgas,
257 Bal,
259 Is,
261 Ret,
263 Retl,
265 Flag,
267}
268
269impl InstOp {
270 pub fn get_type(&self, context: &Context) -> Option<Type> {
275 match self {
276 InstOp::AsmBlock(asm_block, _) => Some(asm_block.return_type),
278 InstOp::UnaryOp { arg, .. } => arg.get_type(context),
279 InstOp::BinaryOp { arg1, .. } => arg1.get_type(context),
280 InstOp::BitCast(_, ty) => Some(*ty),
281 InstOp::Call(function, _) => Some(context.functions[function.0].return_type),
282 InstOp::CastPtr(_val, ty) => Some(*ty),
283 InstOp::Cmp(..) => Some(Type::get_bool(context)),
284 InstOp::ContractCall { return_type, .. } => Some(*return_type),
285 InstOp::FuelVm(FuelVmInstruction::Gtf { .. }) => Some(Type::get_uint64(context)),
286 InstOp::FuelVm(FuelVmInstruction::Log { .. }) => Some(Type::get_unit(context)),
287 InstOp::FuelVm(FuelVmInstruction::ReadRegister(_)) => Some(Type::get_uint64(context)),
288 InstOp::FuelVm(FuelVmInstruction::Smo { .. }) => Some(Type::get_unit(context)),
289
290 InstOp::Load(ptr_val) => match &context.values[ptr_val.0].value {
292 ValueDatum::Argument(arg) => arg.ty.get_pointee_type(context),
293 ValueDatum::Constant(cons) => {
294 cons.get_content(context).ty.get_pointee_type(context)
295 }
296 ValueDatum::Instruction(ins) => ins
297 .get_type(context)
298 .and_then(|ty| ty.get_pointee_type(context)),
299 },
300
301 InstOp::GetElemPtr { elem_ptr_ty, .. } => Some(*elem_ptr_ty),
303 InstOp::GetLocal(local_var) => Some(local_var.get_type(context)),
304 InstOp::GetGlobal(global_var) => Some(global_var.get_type(context)),
305 InstOp::GetConfig(module, name) => Some(match module.get_config(context, name)? {
306 crate::ConfigContent::V0 { ptr_ty, .. } => *ptr_ty,
307 crate::ConfigContent::V1 { ptr_ty, .. } => *ptr_ty,
308 }),
309
310 InstOp::IntToPtr(_, ptr_ty) => Some(*ptr_ty),
312 InstOp::PtrToInt(_, int_ty) => Some(*int_ty),
313
314 InstOp::Branch(_)
316 | InstOp::ConditionalBranch { .. }
317 | InstOp::FuelVm(
318 FuelVmInstruction::Revert(..)
319 | FuelVmInstruction::JmpMem
320 | FuelVmInstruction::Retd { .. },
321 )
322 | InstOp::Ret(..) => None,
323
324 InstOp::Nop => None,
326
327 InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_)) => Some(Type::get_uint64(context)),
329 InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
330 | InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
331 | InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
332 | InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. }) => {
333 Some(Type::get_bool(context))
334 }
335
336 InstOp::MemCopyBytes { .. } | InstOp::MemCopyVal { .. } | InstOp::Store { .. } => {
338 Some(Type::get_unit(context))
339 }
340
341 InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { result, .. }) => {
343 result.get_type(context)
344 }
345 InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { result, .. }) => {
346 result.get_type(context)
347 }
348 InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. }) => Some(Type::get_bool(context)),
349 InstOp::FuelVm(FuelVmInstruction::WideModularOp { result, .. }) => {
350 result.get_type(context)
351 }
352 }
353 }
354
355 pub fn get_operands(&self) -> Vec<Value> {
356 match self {
357 InstOp::AsmBlock(_, args) => args.iter().filter_map(|aa| aa.initializer).collect(),
358 InstOp::BitCast(v, _) => vec![*v],
359 InstOp::UnaryOp { op: _, arg } => vec![*arg],
360 InstOp::BinaryOp { op: _, arg1, arg2 } => vec![*arg1, *arg2],
361 InstOp::Branch(BranchToWithArgs { args, .. }) => args.clone(),
362 InstOp::Call(_, vs) => vs.clone(),
363 InstOp::CastPtr(val, _ty) => vec![*val],
364 InstOp::Cmp(_, lhs, rhs) => vec![*lhs, *rhs],
365 InstOp::ConditionalBranch {
366 cond_value,
367 true_block,
368 false_block,
369 } => {
370 let mut v = vec![*cond_value];
371 v.extend_from_slice(&true_block.args);
372 v.extend_from_slice(&false_block.args);
373 v
374 }
375 InstOp::ContractCall {
376 return_type: _,
377 name: _,
378 params,
379 coins,
380 asset_id,
381 gas,
382 } => vec![*params, *coins, *asset_id, *gas],
383 InstOp::GetElemPtr {
384 base,
385 elem_ptr_ty: _,
386 indices,
387 } => {
388 let mut vals = indices.clone();
389 vals.push(*base);
390 vals
391 }
392 InstOp::GetLocal(_local_var) => {
393 vec![]
395 }
396 InstOp::GetGlobal(_global_var) => {
397 vec![]
399 }
400 InstOp::GetConfig(_, _) => {
401 vec![]
403 }
404 InstOp::IntToPtr(v, _) => vec![*v],
405 InstOp::Load(v) => vec![*v],
406 InstOp::MemCopyBytes {
407 dst_val_ptr,
408 src_val_ptr,
409 byte_len: _,
410 } => {
411 vec![*dst_val_ptr, *src_val_ptr]
412 }
413 InstOp::MemCopyVal {
414 dst_val_ptr,
415 src_val_ptr,
416 } => {
417 vec![*dst_val_ptr, *src_val_ptr]
418 }
419 InstOp::Nop => vec![],
420 InstOp::PtrToInt(v, _) => vec![*v],
421 InstOp::Ret(v, _) => vec![*v],
422 InstOp::Store {
423 dst_val_ptr,
424 stored_val,
425 } => {
426 vec![*dst_val_ptr, *stored_val]
427 }
428
429 InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
430 FuelVmInstruction::Gtf {
431 index,
432 tx_field_id: _,
433 } => vec![*index],
434 FuelVmInstruction::Log {
435 log_val, log_id, ..
436 } => vec![*log_val, *log_id],
437 FuelVmInstruction::ReadRegister(_) => vec![],
438 FuelVmInstruction::Revert(v) => vec![*v],
439 FuelVmInstruction::JmpMem => vec![],
440 FuelVmInstruction::Smo {
441 recipient,
442 message,
443 message_size,
444 coins,
445 } => vec![*recipient, *message, *message_size, *coins],
446 FuelVmInstruction::StateClear {
447 key,
448 number_of_slots,
449 } => vec![*key, *number_of_slots],
450 FuelVmInstruction::StateLoadQuadWord {
451 load_val,
452 key,
453 number_of_slots,
454 } => vec![*load_val, *key, *number_of_slots],
455 FuelVmInstruction::StateLoadWord(key) => vec![*key],
456 FuelVmInstruction::StateStoreQuadWord {
457 stored_val,
458 key,
459 number_of_slots,
460 } => {
461 vec![*stored_val, *key, *number_of_slots]
462 }
463 FuelVmInstruction::StateStoreWord { stored_val, key } => vec![*stored_val, *key],
464 FuelVmInstruction::WideUnaryOp { arg, result, .. } => vec![*result, *arg],
465 FuelVmInstruction::WideBinaryOp {
466 arg1, arg2, result, ..
467 } => vec![*result, *arg1, *arg2],
468 FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => vec![*arg1, *arg2],
469 FuelVmInstruction::WideModularOp {
470 result,
471 arg1,
472 arg2,
473 arg3,
474 ..
475 } => vec![*result, *arg1, *arg2, *arg3],
476 FuelVmInstruction::Retd { ptr, len } => {
477 vec![*ptr, *len]
478 }
479 },
480 }
481 }
482
483 pub fn replace_values(&mut self, replace_map: &FxHashMap<Value, Value>) {
485 let replace = |val: &mut Value| {
486 while let Some(new_val) = replace_map.get(val) {
487 *val = *new_val;
488 }
489 };
490 match self {
491 InstOp::AsmBlock(_, args) => args
492 .iter_mut()
493 .for_each(|asm_arg| asm_arg.initializer.iter_mut().for_each(replace)),
494 InstOp::BitCast(value, _) => replace(value),
495 InstOp::UnaryOp { op: _, arg } => {
496 replace(arg);
497 }
498 InstOp::BinaryOp { op: _, arg1, arg2 } => {
499 replace(arg1);
500 replace(arg2);
501 }
502 InstOp::Branch(block) => {
503 block.args.iter_mut().for_each(replace);
504 }
505 InstOp::Call(_, args) => args.iter_mut().for_each(replace),
506 InstOp::CastPtr(val, _ty) => replace(val),
507 InstOp::Cmp(_, lhs_val, rhs_val) => {
508 replace(lhs_val);
509 replace(rhs_val);
510 }
511 InstOp::ConditionalBranch {
512 cond_value,
513 true_block,
514 false_block,
515 } => {
516 replace(cond_value);
517 true_block.args.iter_mut().for_each(replace);
518 false_block.args.iter_mut().for_each(replace);
519 }
520 InstOp::ContractCall {
521 params,
522 coins,
523 asset_id,
524 gas,
525 ..
526 } => {
527 replace(params);
528 replace(coins);
529 replace(asset_id);
530 replace(gas);
531 }
532 InstOp::GetLocal(_) => (),
533 InstOp::GetGlobal(_) => (),
534 InstOp::GetConfig(_, _) => (),
535 InstOp::GetElemPtr {
536 base,
537 elem_ptr_ty: _,
538 indices,
539 } => {
540 replace(base);
541 indices.iter_mut().for_each(replace);
542 }
543 InstOp::IntToPtr(value, _) => replace(value),
544 InstOp::Load(ptr) => replace(ptr),
545 InstOp::MemCopyBytes {
546 dst_val_ptr,
547 src_val_ptr,
548 ..
549 } => {
550 replace(dst_val_ptr);
551 replace(src_val_ptr);
552 }
553 InstOp::MemCopyVal {
554 dst_val_ptr,
555 src_val_ptr,
556 } => {
557 replace(dst_val_ptr);
558 replace(src_val_ptr);
559 }
560 InstOp::Nop => (),
561 InstOp::PtrToInt(value, _) => replace(value),
562 InstOp::Ret(ret_val, _) => replace(ret_val),
563 InstOp::Store {
564 stored_val,
565 dst_val_ptr,
566 } => {
567 replace(stored_val);
568 replace(dst_val_ptr);
569 }
570
571 InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
572 FuelVmInstruction::Gtf { index, .. } => replace(index),
573 FuelVmInstruction::Log {
574 log_val, log_id, ..
575 } => {
576 replace(log_val);
577 replace(log_id);
578 }
579 FuelVmInstruction::ReadRegister { .. } => (),
580 FuelVmInstruction::Revert(revert_val) => replace(revert_val),
581 FuelVmInstruction::JmpMem => (),
582 FuelVmInstruction::Smo {
583 recipient,
584 message,
585 message_size,
586 coins,
587 } => {
588 replace(recipient);
589 replace(message);
590 replace(message_size);
591 replace(coins);
592 }
593 FuelVmInstruction::StateClear {
594 key,
595 number_of_slots,
596 } => {
597 replace(key);
598 replace(number_of_slots);
599 }
600 FuelVmInstruction::StateLoadQuadWord {
601 load_val,
602 key,
603 number_of_slots,
604 } => {
605 replace(load_val);
606 replace(key);
607 replace(number_of_slots);
608 }
609 FuelVmInstruction::StateLoadWord(key) => {
610 replace(key);
611 }
612 FuelVmInstruction::StateStoreQuadWord {
613 stored_val,
614 key,
615 number_of_slots,
616 } => {
617 replace(key);
618 replace(stored_val);
619 replace(number_of_slots);
620 }
621 FuelVmInstruction::StateStoreWord { stored_val, key } => {
622 replace(key);
623 replace(stored_val);
624 }
625 FuelVmInstruction::WideUnaryOp { arg, result, .. } => {
626 replace(arg);
627 replace(result);
628 }
629 FuelVmInstruction::WideBinaryOp {
630 arg1, arg2, result, ..
631 } => {
632 replace(arg1);
633 replace(arg2);
634 replace(result);
635 }
636 FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => {
637 replace(arg1);
638 replace(arg2);
639 }
640 FuelVmInstruction::WideModularOp {
641 result,
642 arg1,
643 arg2,
644 arg3,
645 ..
646 } => {
647 replace(result);
648 replace(arg1);
649 replace(arg2);
650 replace(arg3);
651 }
652 FuelVmInstruction::Retd { ptr, len } => {
653 replace(ptr);
654 replace(len);
655 }
656 },
657 }
658 }
659
660 pub fn may_have_side_effect(&self) -> bool {
661 match self {
662 InstOp::AsmBlock(asm, _) => !asm.body.is_empty(),
663 InstOp::Call(..)
664 | InstOp::ContractCall { .. }
665 | InstOp::FuelVm(FuelVmInstruction::Log { .. })
666 | InstOp::FuelVm(FuelVmInstruction::Smo { .. })
667 | InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
668 | InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
669 | InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
670 | InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. })
671 | InstOp::FuelVm(FuelVmInstruction::Revert(..))
672 | InstOp::FuelVm(FuelVmInstruction::JmpMem)
673 | InstOp::FuelVm(FuelVmInstruction::Retd { .. })
674 | InstOp::MemCopyBytes { .. }
675 | InstOp::MemCopyVal { .. }
676 | InstOp::Store { .. }
677 | InstOp::Ret(..)
678 | InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { .. })
679 | InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { .. })
680 | InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. })
681 | InstOp::FuelVm(FuelVmInstruction::WideModularOp { .. }) => true,
682
683 InstOp::UnaryOp { .. }
684 | InstOp::BinaryOp { .. }
685 | InstOp::BitCast(..)
686 | InstOp::Branch(_)
687 | InstOp::CastPtr { .. }
688 | InstOp::Cmp(..)
689 | InstOp::ConditionalBranch { .. }
690 | InstOp::FuelVm(FuelVmInstruction::Gtf { .. })
691 | InstOp::FuelVm(FuelVmInstruction::ReadRegister(_))
692 | InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_))
693 | InstOp::GetElemPtr { .. }
694 | InstOp::GetLocal(_)
695 | InstOp::GetGlobal(_)
696 | InstOp::GetConfig(_, _)
697 | InstOp::IntToPtr(..)
698 | InstOp::Load(_)
699 | InstOp::Nop
700 | InstOp::PtrToInt(..) => false,
701 }
702 }
703
704 pub fn is_terminator(&self) -> bool {
705 matches!(
706 self,
707 InstOp::Branch(_)
708 | InstOp::ConditionalBranch { .. }
709 | InstOp::Ret(..)
710 | InstOp::FuelVm(
711 FuelVmInstruction::Revert(..)
712 | FuelVmInstruction::JmpMem
713 | FuelVmInstruction::Retd { .. }
714 )
715 )
716 }
717}
718
719pub struct InstructionIterator {
721 instructions: Vec<slotmap::DefaultKey>,
722 next: usize,
723 next_back: isize,
724}
725
726impl InstructionIterator {
727 pub fn new(context: &Context, block: &Block) -> Self {
728 InstructionIterator {
731 instructions: context.blocks[block.0]
732 .instructions
733 .iter()
734 .map(|val| val.0)
735 .collect(),
736 next: 0,
737 next_back: context.blocks[block.0].instructions.len() as isize - 1,
738 }
739 }
740}
741
742impl Iterator for InstructionIterator {
743 type Item = Value;
744
745 fn next(&mut self) -> Option<Value> {
746 if self.next < self.instructions.len() {
747 let idx = self.next;
748 self.next += 1;
749 Some(Value(self.instructions[idx]))
750 } else {
751 None
752 }
753 }
754}
755
756impl DoubleEndedIterator for InstructionIterator {
757 fn next_back(&mut self) -> Option<Value> {
758 if self.next_back >= 0 {
759 let idx = self.next_back;
760 self.next_back -= 1;
761 Some(Value(self.instructions[idx as usize]))
762 } else {
763 None
764 }
765 }
766}
767
768pub enum InsertionPosition {
770 Start,
772 End,
774 After(Value),
776 Before(Value),
778 At(usize),
780}
781
782pub struct InstructionInserter<'a, 'eng> {
784 context: &'a mut Context<'eng>,
785 block: Block,
786 position: InsertionPosition,
787}
788
789macro_rules! insert_instruction {
790 ($self: ident, $ctor: expr) => {{
791 let instruction_val = Value::new_instruction($self.context, $self.block, $ctor);
792 let pos = $self.get_position_index();
793 let instructions = &mut $self.context.blocks[$self.block.0].instructions;
794 instructions.insert(pos, instruction_val);
795 instruction_val
796 }};
797}
798
799impl<'a, 'eng> InstructionInserter<'a, 'eng> {
800 pub fn new(
802 context: &'a mut Context<'eng>,
803 block: Block,
804 position: InsertionPosition,
805 ) -> InstructionInserter<'a, 'eng> {
806 InstructionInserter {
807 context,
808 block,
809 position,
810 }
811 }
812
813 fn get_position_index(&self) -> usize {
815 let instructions = &self.context.blocks[self.block.0].instructions;
816 match self.position {
817 InsertionPosition::Start => 0,
818 InsertionPosition::End => instructions.len(),
819 InsertionPosition::After(inst) => {
820 instructions
821 .iter()
822 .position(|val| *val == inst)
823 .expect("Provided position for insertion does not exist")
824 + 1
825 }
826 InsertionPosition::Before(inst) => instructions
827 .iter()
828 .position(|val| *val == inst)
829 .expect("Provided position for insertion does not exist"),
830 InsertionPosition::At(pos) => pos,
831 }
832 }
833
834 pub fn insert_slice(&mut self, slice: &[Value]) {
836 let pos = self.get_position_index();
837 self.context.blocks[self.block.0]
838 .instructions
839 .splice(pos..pos, slice.iter().cloned());
840 }
841
842 pub fn insert(&mut self, inst: Value) {
844 let pos = self.get_position_index();
845 self.context.blocks[self.block.0]
846 .instructions
847 .insert(pos, inst);
848 }
849
850 pub fn asm_block(
856 self,
857 args: Vec<AsmArg>,
858 body: Vec<AsmInstruction>,
859 return_type: Type,
860 return_name: Option<Ident>,
861 ) -> Value {
862 let asm = AsmBlock::new(
863 args.iter().map(|arg| arg.name.clone()).collect(),
864 body,
865 return_type,
866 return_name,
867 );
868 self.asm_block_from_asm(asm, args)
869 }
870
871 pub fn asm_block_from_asm(self, asm: AsmBlock, args: Vec<AsmArg>) -> Value {
872 insert_instruction!(self, InstOp::AsmBlock(asm, args))
873 }
874
875 pub fn bitcast(self, value: Value, ty: Type) -> Value {
876 insert_instruction!(self, InstOp::BitCast(value, ty))
877 }
878
879 pub fn unary_op(self, op: UnaryOpKind, arg: Value) -> Value {
880 insert_instruction!(self, InstOp::UnaryOp { op, arg })
881 }
882
883 pub fn wide_unary_op(self, op: UnaryOpKind, arg: Value, result: Value) -> Value {
884 insert_instruction!(
885 self,
886 InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { op, arg, result })
887 )
888 }
889
890 pub fn wide_binary_op(
891 self,
892 op: BinaryOpKind,
893 arg1: Value,
894 arg2: Value,
895 result: Value,
896 ) -> Value {
897 insert_instruction!(
898 self,
899 InstOp::FuelVm(FuelVmInstruction::WideBinaryOp {
900 op,
901 arg1,
902 arg2,
903 result
904 })
905 )
906 }
907
908 pub fn wide_modular_op(
909 self,
910 op: BinaryOpKind,
911 result: Value,
912 arg1: Value,
913 arg2: Value,
914 arg3: Value,
915 ) -> Value {
916 insert_instruction!(
917 self,
918 InstOp::FuelVm(FuelVmInstruction::WideModularOp {
919 op,
920 result,
921 arg1,
922 arg2,
923 arg3,
924 })
925 )
926 }
927
928 pub fn wide_cmp_op(self, op: Predicate, arg1: Value, arg2: Value) -> Value {
929 insert_instruction!(
930 self,
931 InstOp::FuelVm(FuelVmInstruction::WideCmpOp { op, arg1, arg2 })
932 )
933 }
934
935 pub fn binary_op(self, op: BinaryOpKind, arg1: Value, arg2: Value) -> Value {
936 insert_instruction!(self, InstOp::BinaryOp { op, arg1, arg2 })
937 }
938
939 pub fn branch(self, to_block: Block, dest_params: Vec<Value>) -> Value {
940 let br_val = Value::new_instruction(
941 self.context,
942 self.block,
943 InstOp::Branch(BranchToWithArgs {
944 block: to_block,
945 args: dest_params,
946 }),
947 );
948 to_block.add_pred(self.context, &self.block);
949 self.context.blocks[self.block.0].instructions.push(br_val);
950 br_val
951 }
952
953 pub fn call(self, function: Function, args: &[Value]) -> Value {
954 insert_instruction!(self, InstOp::Call(function, args.to_vec()))
955 }
956
957 pub fn cast_ptr(self, val: Value, ty: Type) -> Value {
958 insert_instruction!(self, InstOp::CastPtr(val, ty))
959 }
960
961 pub fn cmp(self, pred: Predicate, lhs_value: Value, rhs_value: Value) -> Value {
962 insert_instruction!(self, InstOp::Cmp(pred, lhs_value, rhs_value))
963 }
964
965 pub fn conditional_branch(
966 self,
967 cond_value: Value,
968 true_block: Block,
969 false_block: Block,
970 true_dest_params: Vec<Value>,
971 false_dest_params: Vec<Value>,
972 ) -> Value {
973 let cbr_val = Value::new_instruction(
974 self.context,
975 self.block,
976 InstOp::ConditionalBranch {
977 cond_value,
978 true_block: BranchToWithArgs {
979 block: true_block,
980 args: true_dest_params,
981 },
982 false_block: BranchToWithArgs {
983 block: false_block,
984 args: false_dest_params,
985 },
986 },
987 );
988 true_block.add_pred(self.context, &self.block);
989 false_block.add_pred(self.context, &self.block);
990 self.context.blocks[self.block.0].instructions.push(cbr_val);
991 cbr_val
992 }
993
994 pub fn contract_call(
995 self,
996 return_type: Type,
997 name: Option<String>,
998 params: Value,
999 coins: Value, asset_id: Value, gas: Value, ) -> Value {
1003 insert_instruction!(
1004 self,
1005 InstOp::ContractCall {
1006 return_type,
1007 name,
1008 params,
1009 coins,
1010 asset_id,
1011 gas,
1012 }
1013 )
1014 }
1015
1016 pub fn gtf(self, index: Value, tx_field_id: u64) -> Value {
1017 insert_instruction!(
1018 self,
1019 InstOp::FuelVm(FuelVmInstruction::Gtf { index, tx_field_id })
1020 )
1021 }
1022
1023 pub fn get_elem_ptr(self, base: Value, elem_ty: Type, indices: Vec<Value>) -> Value {
1026 let elem_ptr_ty = Type::new_ptr(self.context, elem_ty);
1027 insert_instruction!(
1028 self,
1029 InstOp::GetElemPtr {
1030 base,
1031 elem_ptr_ty,
1032 indices
1033 }
1034 )
1035 }
1036
1037 pub fn get_elem_ptr_with_idx(self, base: Value, elem_ty: Type, index: u64) -> Value {
1038 let idx_val = ConstantContent::get_uint(self.context, 64, index);
1039 self.get_elem_ptr(base, elem_ty, vec![idx_val])
1040 }
1041
1042 pub fn get_elem_ptr_with_idcs(self, base: Value, elem_ty: Type, indices: &[u64]) -> Value {
1043 let idx_vals = indices
1044 .iter()
1045 .map(|idx| ConstantContent::get_uint(self.context, 64, *idx))
1046 .collect();
1047 self.get_elem_ptr(base, elem_ty, idx_vals)
1048 }
1049
1050 pub fn get_local(self, local_var: LocalVar) -> Value {
1051 insert_instruction!(self, InstOp::GetLocal(local_var))
1052 }
1053
1054 pub fn get_global(self, global_var: GlobalVar) -> Value {
1055 insert_instruction!(self, InstOp::GetGlobal(global_var))
1056 }
1057
1058 pub fn get_config(self, module: Module, name: String) -> Value {
1059 insert_instruction!(self, InstOp::GetConfig(module, name))
1060 }
1061
1062 pub fn int_to_ptr(self, value: Value, ty: Type) -> Value {
1063 insert_instruction!(self, InstOp::IntToPtr(value, ty))
1064 }
1065
1066 pub fn load(self, src_val: Value) -> Value {
1067 insert_instruction!(self, InstOp::Load(src_val))
1068 }
1069
1070 pub fn log(self, log_val: Value, log_ty: Type, log_id: Value) -> Value {
1071 insert_instruction!(
1072 self,
1073 InstOp::FuelVm(FuelVmInstruction::Log {
1074 log_val,
1075 log_ty,
1076 log_id
1077 })
1078 )
1079 }
1080
1081 pub fn mem_copy_bytes(self, dst_val_ptr: Value, src_val_ptr: Value, byte_len: u64) -> Value {
1082 insert_instruction!(
1083 self,
1084 InstOp::MemCopyBytes {
1085 dst_val_ptr,
1086 src_val_ptr,
1087 byte_len
1088 }
1089 )
1090 }
1091
1092 pub fn mem_copy_val(self, dst_val_ptr: Value, src_val_ptr: Value) -> Value {
1093 insert_instruction!(
1094 self,
1095 InstOp::MemCopyVal {
1096 dst_val_ptr,
1097 src_val_ptr,
1098 }
1099 )
1100 }
1101
1102 pub fn nop(self) -> Value {
1103 insert_instruction!(self, InstOp::Nop)
1104 }
1105
1106 pub fn ptr_to_int(self, value: Value, ty: Type) -> Value {
1107 insert_instruction!(self, InstOp::PtrToInt(value, ty))
1108 }
1109
1110 pub fn read_register(self, reg: Register) -> Value {
1111 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::ReadRegister(reg)))
1112 }
1113
1114 pub fn ret(self, value: Value, ty: Type) -> Value {
1115 insert_instruction!(self, InstOp::Ret(value, ty))
1116 }
1117
1118 pub fn retd(self, ptr: Value, len: Value) -> Value {
1119 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::Retd { ptr, len }))
1120 }
1121
1122 pub fn revert(self, value: Value) -> Value {
1123 let revert_val = Value::new_instruction(
1124 self.context,
1125 self.block,
1126 InstOp::FuelVm(FuelVmInstruction::Revert(value)),
1127 );
1128 self.context.blocks[self.block.0]
1129 .instructions
1130 .push(revert_val);
1131 revert_val
1132 }
1133
1134 pub fn jmp_mem(self) -> Value {
1135 let ldc_exec = Value::new_instruction(
1136 self.context,
1137 self.block,
1138 InstOp::FuelVm(FuelVmInstruction::JmpMem),
1139 );
1140 self.context.blocks[self.block.0]
1141 .instructions
1142 .push(ldc_exec);
1143 ldc_exec
1144 }
1145
1146 pub fn smo(self, recipient: Value, message: Value, message_size: Value, coins: Value) -> Value {
1147 insert_instruction!(
1148 self,
1149 InstOp::FuelVm(FuelVmInstruction::Smo {
1150 recipient,
1151 message,
1152 message_size,
1153 coins,
1154 })
1155 )
1156 }
1157
1158 pub fn state_clear(self, key: Value, number_of_slots: Value) -> Value {
1159 insert_instruction!(
1160 self,
1161 InstOp::FuelVm(FuelVmInstruction::StateClear {
1162 key,
1163 number_of_slots
1164 })
1165 )
1166 }
1167
1168 pub fn state_load_quad_word(
1169 self,
1170 load_val: Value,
1171 key: Value,
1172 number_of_slots: Value,
1173 ) -> Value {
1174 insert_instruction!(
1175 self,
1176 InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord {
1177 load_val,
1178 key,
1179 number_of_slots
1180 })
1181 )
1182 }
1183
1184 pub fn state_load_word(self, key: Value) -> Value {
1185 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::StateLoadWord(key)))
1186 }
1187
1188 pub fn state_store_quad_word(
1189 self,
1190 stored_val: Value,
1191 key: Value,
1192 number_of_slots: Value,
1193 ) -> Value {
1194 insert_instruction!(
1195 self,
1196 InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord {
1197 stored_val,
1198 key,
1199 number_of_slots
1200 })
1201 )
1202 }
1203
1204 pub fn state_store_word(self, stored_val: Value, key: Value) -> Value {
1205 insert_instruction!(
1206 self,
1207 InstOp::FuelVm(FuelVmInstruction::StateStoreWord { stored_val, key })
1208 )
1209 }
1210
1211 pub fn store(self, dst_val_ptr: Value, stored_val: Value) -> Value {
1212 insert_instruction!(
1213 self,
1214 InstOp::Store {
1215 dst_val_ptr,
1216 stored_val,
1217 }
1218 )
1219 }
1220}