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, StorageKey,
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 pub fn get_function(&self, context: &Context) -> Function {
47 context.blocks[self.parent.0].function
48 }
49}
50
51#[derive(Debug, Clone, DebugWithContext)]
52pub enum InstOp {
53 AsmBlock(AsmBlock, Vec<AsmArg>),
55 UnaryOp {
57 op: UnaryOpKind,
58 arg: Value,
59 },
60 BinaryOp {
62 op: BinaryOpKind,
63 arg1: Value,
64 arg2: Value,
65 },
66 BitCast(Value, Type),
68 Branch(BranchToWithArgs),
70 Call(Function, Vec<Value>),
72 CastPtr(Value, Type),
74 Cmp(Predicate, Value, Value),
76 ConditionalBranch {
78 cond_value: Value,
79 true_block: BranchToWithArgs,
80 false_block: BranchToWithArgs,
81 },
82 ContractCall {
84 return_type: Type,
85 name: Option<String>,
86 params: Value,
87 coins: Value,
88 asset_id: Value,
89 gas: Value,
90 },
91 FuelVm(FuelVmInstruction),
93 GetLocal(LocalVar),
95 GetGlobal(GlobalVar),
97 GetConfig(Module, String),
99 GetStorageKey(StorageKey),
100 GetElemPtr {
102 base: Value,
103 elem_ptr_ty: Type,
104 indices: Vec<Value>,
105 },
106 IntToPtr(Value, Type),
108 Load(Value),
110 MemCopyBytes {
112 dst_val_ptr: Value,
113 src_val_ptr: Value,
114 byte_len: u64,
115 },
116 MemCopyVal {
118 dst_val_ptr: Value,
119 src_val_ptr: Value,
120 },
121 MemClearVal {
123 dst_val_ptr: Value,
124 },
125 Nop,
127 PtrToInt(Value, Type),
129 Ret(Value, Type),
131 Store {
133 dst_val_ptr: Value,
134 stored_val: Value,
135 },
136 Alloc {
138 ty: Type,
139 count: Value,
140 },
141}
142
143#[derive(Debug, Clone, Copy, DebugWithContext)]
153pub struct LogEventData {
154 version: u8,
155 is_event: bool,
156 is_indexed: bool,
157 event_type_size: u8,
158 num_elements: u16,
159}
160
161impl Default for LogEventData {
162 fn default() -> Self {
163 Self {
164 version: Self::CURRENT_VERSION,
165 is_event: false,
166 is_indexed: false,
167 event_type_size: 0,
168 num_elements: 0,
169 }
170 }
171}
172
173impl LogEventData {
174 pub const CURRENT_VERSION: u8 = 0;
175
176 pub fn new(
177 version: u8,
178 is_event: bool,
179 is_indexed: bool,
180 event_type_size: u8,
181 num_elements: u16,
182 ) -> Self {
183 Self {
184 version,
185 is_event,
186 is_indexed,
187 event_type_size,
188 num_elements,
189 }
190 }
191
192 pub fn for_event(indexed_field_size: Option<u8>, indexed_field_count: u16) -> Self {
193 match (indexed_field_size, indexed_field_count) {
194 (Some(size), count) if count > 0 => Self {
195 version: Self::CURRENT_VERSION,
196 is_event: true,
197 is_indexed: true,
198 event_type_size: size,
199 num_elements: count,
200 },
201 _ => Self {
202 version: Self::CURRENT_VERSION,
203 is_event: true,
204 is_indexed: false,
205 event_type_size: 0,
206 num_elements: 0,
207 },
208 }
209 }
210
211 pub fn version(&self) -> u8 {
212 self.version
213 }
214
215 pub fn is_event(&self) -> bool {
216 self.is_event
217 }
218
219 pub fn is_indexed(&self) -> bool {
220 self.is_indexed
221 }
222
223 pub fn event_type_size(&self) -> u8 {
224 self.event_type_size
225 }
226
227 pub fn num_elements(&self) -> u16 {
228 self.num_elements
229 }
230
231 pub fn encoded(&self) -> u64 {
237 (u64::from(self.version) << 56)
238 | (u64::from(self.is_event as u8) << 48)
239 | (u64::from(self.is_indexed as u8) << 40)
240 | (u64::from(self.event_type_size) << 32)
241 | (u64::from(self.num_elements) << 16)
242 }
243}
244
245#[derive(Debug, Clone, DebugWithContext)]
246pub enum FuelVmInstruction {
247 Gtf {
248 index: Value,
249 tx_field_id: u64,
250 },
251 Log {
253 log_val: Value,
254 log_ty: Type,
255 log_id: Value,
256 log_data: Option<LogEventData>,
257 },
258 ReadRegister(Register),
260 Revert(Value),
262 Smo {
267 recipient: Value,
268 message: Value,
269 message_size: Value,
270 coins: Value,
271 },
272 StateClear {
274 key: Value,
275 number_of_slots: Value,
276 },
277 StateLoadQuadWord {
280 load_val: Value,
281 key: Value,
282 number_of_slots: Value,
283 },
284 StateLoadWord(Value),
286 StateStoreQuadWord {
289 stored_val: Value,
290 key: Value,
291 number_of_slots: Value,
292 },
293 StateStoreWord {
296 stored_val: Value,
297 key: Value,
298 },
299 WideUnaryOp {
300 op: UnaryOpKind,
301 result: Value,
302 arg: Value,
303 },
304 WideBinaryOp {
305 op: BinaryOpKind,
306 result: Value,
307 arg1: Value,
308 arg2: Value,
309 },
310 WideModularOp {
311 op: BinaryOpKind,
312 result: Value,
313 arg1: Value,
314 arg2: Value,
315 arg3: Value,
316 },
317 WideCmpOp {
318 op: Predicate,
319 arg1: Value,
320 arg2: Value,
321 },
322 JmpMem,
323 Retd {
324 ptr: Value,
325 len: Value,
326 },
327}
328
329#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
331pub enum Predicate {
332 Equal,
333 LessThan,
334 GreaterThan,
335}
336
337#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
338pub enum UnaryOpKind {
339 Not,
340}
341
342#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
343pub enum BinaryOpKind {
344 Add,
345 Sub,
346 Mul,
347 Div,
348 And,
349 Or,
350 Xor,
351 Mod,
352 Rsh,
353 Lsh,
354}
355
356#[derive(Debug, Clone, Copy, Hash)]
358pub enum Register {
359 Of,
361 Pc,
363 Ssp,
365 Sp,
367 Fp,
369 Hp,
371 Error,
373 Ggas,
375 Cgas,
377 Bal,
379 Is,
381 Ret,
383 Retl,
385 Flag,
387}
388
389impl InstOp {
390 pub fn get_type(&self, context: &Context) -> Option<Type> {
395 match self {
396 InstOp::AsmBlock(asm_block, _) => Some(asm_block.return_type),
398 InstOp::UnaryOp { arg, .. } => arg.get_type(context),
399 InstOp::BinaryOp { arg1, .. } => arg1.get_type(context),
400 InstOp::BitCast(_, ty) => Some(*ty),
401 InstOp::Call(function, _) => Some(context.functions[function.0].return_type),
402 InstOp::CastPtr(_val, ty) => Some(*ty),
403 InstOp::Cmp(..) => Some(Type::get_bool(context)),
404 InstOp::ContractCall { return_type, .. } => Some(*return_type),
405 InstOp::FuelVm(FuelVmInstruction::Gtf { .. }) => Some(Type::get_uint64(context)),
406 InstOp::FuelVm(FuelVmInstruction::Log { .. }) => Some(Type::get_unit(context)),
407 InstOp::FuelVm(FuelVmInstruction::ReadRegister(_)) => Some(Type::get_uint64(context)),
408 InstOp::FuelVm(FuelVmInstruction::Smo { .. }) => Some(Type::get_unit(context)),
409
410 InstOp::Load(ptr_val) => match &context.values[ptr_val.0].value {
412 ValueDatum::Argument(arg) => arg.ty.get_pointee_type(context),
413 ValueDatum::Constant(cons) => {
414 cons.get_content(context).ty.get_pointee_type(context)
415 }
416 ValueDatum::Instruction(ins) => ins
417 .get_type(context)
418 .and_then(|ty| ty.get_pointee_type(context)),
419 },
420
421 InstOp::GetElemPtr { elem_ptr_ty, .. } => Some(*elem_ptr_ty),
423 InstOp::GetLocal(local_var) => Some(local_var.get_type(context)),
424 InstOp::GetGlobal(global_var) => Some(global_var.get_type(context)),
425 InstOp::GetConfig(module, name) => Some(match module.get_config(context, name)? {
426 crate::ConfigContent::V0 { ptr_ty, .. } => *ptr_ty,
427 crate::ConfigContent::V1 { ptr_ty, .. } => *ptr_ty,
428 }),
429 InstOp::GetStorageKey(storage_key) => Some(storage_key.get_type(context)),
430 InstOp::Alloc { ty: _, count: _ } => Some(Type::get_ptr(context)),
431
432 InstOp::IntToPtr(_, ptr_ty) => Some(*ptr_ty),
434 InstOp::PtrToInt(_, int_ty) => Some(*int_ty),
435
436 InstOp::Branch(_)
438 | InstOp::ConditionalBranch { .. }
439 | InstOp::FuelVm(
440 FuelVmInstruction::Revert(..)
441 | FuelVmInstruction::JmpMem
442 | FuelVmInstruction::Retd { .. },
443 )
444 | InstOp::Ret(..) => None,
445
446 InstOp::Nop => None,
448
449 InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_)) => Some(Type::get_uint64(context)),
451 InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
452 | InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
453 | InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
454 | InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. }) => {
455 Some(Type::get_bool(context))
456 }
457
458 InstOp::MemCopyBytes { .. }
460 | InstOp::MemCopyVal { .. }
461 | InstOp::MemClearVal { .. }
462 | InstOp::Store { .. } => Some(Type::get_unit(context)),
463
464 InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { result, .. }) => {
466 result.get_type(context)
467 }
468 InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { result, .. }) => {
469 result.get_type(context)
470 }
471 InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. }) => Some(Type::get_bool(context)),
472 InstOp::FuelVm(FuelVmInstruction::WideModularOp { result, .. }) => {
473 result.get_type(context)
474 }
475 }
476 }
477
478 pub fn get_operands(&self) -> Vec<Value> {
479 match self {
480 InstOp::AsmBlock(_, args) => args.iter().filter_map(|aa| aa.initializer).collect(),
481 InstOp::BitCast(v, _) => vec![*v],
482 InstOp::UnaryOp { op: _, arg } => vec![*arg],
483 InstOp::BinaryOp { op: _, arg1, arg2 } => vec![*arg1, *arg2],
484 InstOp::Branch(BranchToWithArgs { args, .. }) => args.clone(),
485 InstOp::Call(_, vs) => vs.clone(),
486 InstOp::CastPtr(val, _ty) => vec![*val],
487 InstOp::Cmp(_, lhs, rhs) => vec![*lhs, *rhs],
488 InstOp::ConditionalBranch {
489 cond_value,
490 true_block,
491 false_block,
492 } => {
493 let mut v = vec![*cond_value];
494 v.extend_from_slice(&true_block.args);
495 v.extend_from_slice(&false_block.args);
496 v
497 }
498 InstOp::ContractCall {
499 return_type: _,
500 name: _,
501 params,
502 coins,
503 asset_id,
504 gas,
505 } => vec![*params, *coins, *asset_id, *gas],
506 InstOp::GetElemPtr {
507 base,
508 elem_ptr_ty: _,
509 indices,
510 } => {
511 let mut vals = indices.clone();
512 vals.push(*base);
513 vals
514 }
515 InstOp::GetLocal(_local_var) => {
516 vec![]
518 }
519 InstOp::GetGlobal(_global_var) => {
520 vec![]
522 }
523 InstOp::GetConfig(_, _) => {
524 vec![]
526 }
527 InstOp::GetStorageKey(_) => {
528 vec![]
530 }
531 InstOp::Alloc { ty: _, count } => vec![*count],
532 InstOp::IntToPtr(v, _) => vec![*v],
533 InstOp::Load(v) => vec![*v],
534 InstOp::MemCopyBytes {
535 dst_val_ptr,
536 src_val_ptr,
537 byte_len: _,
538 } => {
539 vec![*dst_val_ptr, *src_val_ptr]
540 }
541 InstOp::MemCopyVal {
542 dst_val_ptr,
543 src_val_ptr,
544 } => {
545 vec![*dst_val_ptr, *src_val_ptr]
546 }
547 InstOp::MemClearVal { dst_val_ptr } => {
548 vec![*dst_val_ptr]
549 }
550 InstOp::Nop => vec![],
551 InstOp::PtrToInt(v, _) => vec![*v],
552 InstOp::Ret(v, _) => vec![*v],
553 InstOp::Store {
554 dst_val_ptr,
555 stored_val,
556 } => {
557 vec![*dst_val_ptr, *stored_val]
558 }
559
560 InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
561 FuelVmInstruction::Gtf {
562 index,
563 tx_field_id: _,
564 } => vec![*index],
565 FuelVmInstruction::Log {
566 log_val, log_id, ..
567 } => vec![*log_val, *log_id],
568 FuelVmInstruction::ReadRegister(_) => vec![],
569 FuelVmInstruction::Revert(v) => vec![*v],
570 FuelVmInstruction::JmpMem => vec![],
571 FuelVmInstruction::Smo {
572 recipient,
573 message,
574 message_size,
575 coins,
576 } => vec![*recipient, *message, *message_size, *coins],
577 FuelVmInstruction::StateClear {
578 key,
579 number_of_slots,
580 } => vec![*key, *number_of_slots],
581 FuelVmInstruction::StateLoadQuadWord {
582 load_val,
583 key,
584 number_of_slots,
585 } => vec![*load_val, *key, *number_of_slots],
586 FuelVmInstruction::StateLoadWord(key) => vec![*key],
587 FuelVmInstruction::StateStoreQuadWord {
588 stored_val,
589 key,
590 number_of_slots,
591 } => {
592 vec![*stored_val, *key, *number_of_slots]
593 }
594 FuelVmInstruction::StateStoreWord { stored_val, key } => vec![*stored_val, *key],
595 FuelVmInstruction::WideUnaryOp { arg, result, .. } => vec![*result, *arg],
596 FuelVmInstruction::WideBinaryOp {
597 arg1, arg2, result, ..
598 } => vec![*result, *arg1, *arg2],
599 FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => vec![*arg1, *arg2],
600 FuelVmInstruction::WideModularOp {
601 result,
602 arg1,
603 arg2,
604 arg3,
605 ..
606 } => vec![*result, *arg1, *arg2, *arg3],
607 FuelVmInstruction::Retd { ptr, len } => {
608 vec![*ptr, *len]
609 }
610 },
611 }
612 }
613
614 pub fn set_operand(&mut self, replacement: Value, idx: usize) {
617 match self {
618 InstOp::AsmBlock(_, args) => {
619 let mut cur_idx = 0;
622 for arg in args.iter_mut() {
623 if let Some(_asm_arg) = arg.initializer {
624 if cur_idx == idx {
625 arg.initializer = Some(replacement);
626 return;
627 }
628 cur_idx += 1;
629 }
630 }
631 panic!("Invalid index for AsmBlock");
632 }
633 InstOp::BitCast(v, _) | InstOp::UnaryOp { arg: v, .. } => {
634 if idx == 0 {
635 *v = replacement;
636 } else {
637 panic!("Invalid index for Op");
638 }
639 }
640 InstOp::BinaryOp { op: _, arg1, arg2 } => {
641 if idx == 0 {
642 *arg1 = replacement;
643 } else if idx == 1 {
644 *arg2 = replacement;
645 } else {
646 panic!("Invalid index for BinaryOp");
647 }
648 }
649 InstOp::Branch(BranchToWithArgs { args, .. }) => {
650 if idx < args.len() {
651 args[idx] = replacement;
652 } else {
653 panic!("Invalid index for Branch");
654 }
655 }
656 InstOp::Call(_, vs) => {
657 if idx < vs.len() {
658 vs[idx] = replacement;
659 } else {
660 panic!("Invalid index for Call");
661 }
662 }
663 InstOp::CastPtr(val, _ty) => {
664 if idx == 0 {
665 *val = replacement;
666 } else {
667 panic!("Invalid index for CastPtr");
668 }
669 }
670 InstOp::Cmp(_, lhs, rhs) => {
671 if idx == 0 {
672 *lhs = replacement;
673 } else if idx == 1 {
674 *rhs = replacement;
675 } else {
676 panic!("Invalid index for Cmp");
677 }
678 }
679 InstOp::ConditionalBranch {
680 cond_value,
681 true_block,
682 false_block,
683 } => {
684 if idx == 0 {
685 *cond_value = replacement;
686 } else if idx - 1 < true_block.args.len() {
687 true_block.args[idx - 1] = replacement;
688 } else if idx - 1 - true_block.args.len() < false_block.args.len() {
689 false_block.args[idx - 1 - true_block.args.len()] = replacement;
690 } else {
691 panic!("Invalid index for ConditionalBranch");
692 }
693 }
694 InstOp::ContractCall {
695 return_type: _,
696 name: _,
697 params,
698 coins,
699 asset_id,
700 gas,
701 } => {
702 if idx == 0 {
703 *params = replacement;
704 } else if idx == 1 {
705 *coins = replacement;
706 } else if idx == 2 {
707 *asset_id = replacement;
708 } else if idx == 3 {
709 *gas = replacement;
710 } else {
711 panic!("Invalid index for ContractCall");
712 }
713 }
714 InstOp::GetElemPtr {
715 base,
716 elem_ptr_ty: _,
717 indices,
718 } => {
719 use std::cmp::Ordering;
720 match idx.cmp(&indices.len()) {
721 Ordering::Less => {
722 indices[idx] = replacement;
723 }
724 Ordering::Equal => {
725 *base = replacement;
726 }
727 Ordering::Greater => {
728 panic!("Invalid index for GetElemPtr");
729 }
730 }
731 }
732 InstOp::GetLocal(_local_var) => {
733 panic!("Invalid index for GetLocal");
735 }
736 InstOp::GetGlobal(_global_var) => {
737 panic!("Invalid index for GetGlobal");
739 }
740 InstOp::GetConfig(_, _) => {
741 panic!("Invalid index for GetConfig");
743 }
744 InstOp::GetStorageKey(_) => {
745 panic!("Invalid index for GetStorageKey");
747 }
748 InstOp::Alloc { ty: _, count } => {
749 if idx == 0 {
750 *count = replacement;
751 } else {
752 panic!("Invalid index for Alloc");
753 }
754 }
755 InstOp::IntToPtr(v, _) => {
756 if idx == 0 {
757 *v = replacement;
758 } else {
759 panic!("Invalid index for IntToPtr");
760 }
761 }
762 InstOp::Load(v) => {
763 if idx == 0 {
764 *v = replacement;
765 } else {
766 panic!("Invalid index for Load");
767 }
768 }
769 InstOp::MemCopyBytes {
770 dst_val_ptr,
771 src_val_ptr,
772 byte_len: _,
773 } => {
774 if idx == 0 {
775 *dst_val_ptr = replacement;
776 } else if idx == 1 {
777 *src_val_ptr = replacement;
778 } else {
779 panic!("Invalid index for MemCopyBytes");
780 }
781 }
782 InstOp::MemCopyVal {
783 dst_val_ptr,
784 src_val_ptr,
785 } => {
786 if idx == 0 {
787 *dst_val_ptr = replacement;
788 } else if idx == 1 {
789 *src_val_ptr = replacement;
790 } else {
791 panic!("Invalid index for MemCopyVal");
792 }
793 }
794 InstOp::MemClearVal { dst_val_ptr } => {
795 if idx == 0 {
796 *dst_val_ptr = replacement;
797 } else {
798 panic!("Invalid index for MemClearVal");
799 }
800 }
801 InstOp::Nop => (),
802 InstOp::PtrToInt(v, _) => {
803 if idx == 0 {
804 *v = replacement;
805 } else {
806 panic!("Invalid index for PtrToInt");
807 }
808 }
809 InstOp::Ret(v, _) => {
810 if idx == 0 {
811 *v = replacement;
812 } else {
813 panic!("Invalid index for Ret");
814 }
815 }
816 InstOp::Store {
817 dst_val_ptr,
818 stored_val,
819 } => {
820 if idx == 0 {
821 *dst_val_ptr = replacement;
822 } else if idx == 1 {
823 *stored_val = replacement;
824 } else {
825 panic!("Invalid index for Store");
826 }
827 }
828
829 InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
830 FuelVmInstruction::Gtf {
831 index,
832 tx_field_id: _,
833 } => {
834 if idx == 0 {
835 *index = replacement;
836 } else {
837 panic!("Invalid index for Gtf");
838 }
839 }
840 FuelVmInstruction::Log {
841 log_val, log_id, ..
842 } => {
843 if idx == 0 {
844 *log_val = replacement;
845 } else if idx == 1 {
846 *log_id = replacement;
847 } else {
848 panic!("Invalid index for Log");
849 }
850 }
851 FuelVmInstruction::ReadRegister(_) => {
852 panic!("Invalid index for ReadRegister");
854 }
855 FuelVmInstruction::Revert(v) => {
856 if idx == 0 {
857 *v = replacement;
858 } else {
859 panic!("Invalid index for Revert");
860 }
861 }
862 FuelVmInstruction::JmpMem => {
863 panic!("Invalid index for JmpMem");
865 }
866 FuelVmInstruction::Smo {
867 recipient,
868 message,
869 message_size,
870 coins,
871 } => {
872 if idx == 0 {
873 *recipient = replacement;
874 } else if idx == 1 {
875 *message = replacement;
876 } else if idx == 2 {
877 *message_size = replacement;
878 } else if idx == 3 {
879 *coins = replacement;
880 } else {
881 panic!("Invalid index for Smo");
882 }
883 }
884 FuelVmInstruction::StateClear {
885 key,
886 number_of_slots,
887 } => {
888 if idx == 0 {
889 *key = replacement;
890 } else if idx == 1 {
891 *number_of_slots = replacement;
892 } else {
893 panic!("Invalid index for StateClear");
894 }
895 }
896 FuelVmInstruction::StateLoadQuadWord {
897 load_val,
898 key,
899 number_of_slots,
900 } => {
901 if idx == 0 {
902 *load_val = replacement;
903 } else if idx == 1 {
904 *key = replacement;
905 } else if idx == 2 {
906 *number_of_slots = replacement;
907 } else {
908 panic!("Invalid index for StateLoadQuadWord");
909 }
910 }
911 FuelVmInstruction::StateLoadWord(key) => {
912 if idx == 0 {
913 *key = replacement;
914 } else {
915 panic!("Invalid index for StateLoadWord");
916 }
917 }
918 FuelVmInstruction::StateStoreQuadWord {
919 stored_val,
920 key,
921 number_of_slots,
922 } => {
923 if idx == 0 {
924 *stored_val = replacement;
925 } else if idx == 1 {
926 *key = replacement;
927 } else if idx == 2 {
928 *number_of_slots = replacement;
929 } else {
930 panic!("Invalid index for StateStoreQuadWord");
931 }
932 }
933 FuelVmInstruction::StateStoreWord { stored_val, key } => {
934 if idx == 0 {
935 *stored_val = replacement;
936 } else if idx == 1 {
937 *key = replacement;
938 } else {
939 panic!("Invalid index for StateStoreWord");
940 }
941 }
942 FuelVmInstruction::WideUnaryOp { arg, result, .. } => {
943 if idx == 0 {
944 *result = replacement;
945 } else if idx == 1 {
946 *arg = replacement;
947 } else {
948 panic!("Invalid index for WideUnaryOp");
949 }
950 }
951 FuelVmInstruction::WideBinaryOp {
952 arg1, arg2, result, ..
953 } => {
954 if idx == 0 {
955 *result = replacement;
956 } else if idx == 1 {
957 *arg1 = replacement;
958 } else if idx == 2 {
959 *arg2 = replacement;
960 } else {
961 panic!("Invalid index for WideBinaryOp");
962 }
963 }
964 FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => {
965 if idx == 0 {
966 *arg1 = replacement;
967 } else if idx == 1 {
968 *arg2 = replacement;
969 } else {
970 panic!("Invalid index for WideCmpOp");
971 }
972 }
973 FuelVmInstruction::WideModularOp {
974 result,
975 arg1,
976 arg2,
977 arg3,
978 ..
979 } => {
980 if idx == 0 {
981 *result = replacement;
982 } else if idx == 1 {
983 *arg1 = replacement;
984 } else if idx == 2 {
985 *arg2 = replacement;
986 } else if idx == 3 {
987 *arg3 = replacement;
988 } else {
989 panic!("Invalid index for WideModularOp");
990 }
991 }
992 FuelVmInstruction::Retd { ptr, len } => {
993 if idx == 0 {
994 *ptr = replacement;
995 } else if idx == 1 {
996 *len = replacement;
997 } else {
998 panic!("Invalid index for Retd");
999 }
1000 }
1001 },
1002 }
1003 }
1004
1005 pub fn replace_values(&mut self, replace_map: &FxHashMap<Value, Value>) {
1007 let replace = |val: &mut Value| {
1008 while let Some(new_val) = replace_map.get(val) {
1009 *val = *new_val;
1010 }
1011 };
1012 match self {
1013 InstOp::AsmBlock(_, args) => args
1014 .iter_mut()
1015 .for_each(|asm_arg| asm_arg.initializer.iter_mut().for_each(replace)),
1016 InstOp::BitCast(value, _) => replace(value),
1017 InstOp::UnaryOp { op: _, arg } => {
1018 replace(arg);
1019 }
1020 InstOp::BinaryOp { op: _, arg1, arg2 } => {
1021 replace(arg1);
1022 replace(arg2);
1023 }
1024 InstOp::Branch(block) => {
1025 block.args.iter_mut().for_each(replace);
1026 }
1027 InstOp::Call(_, args) => args.iter_mut().for_each(replace),
1028 InstOp::CastPtr(val, _ty) => replace(val),
1029 InstOp::Cmp(_, lhs_val, rhs_val) => {
1030 replace(lhs_val);
1031 replace(rhs_val);
1032 }
1033 InstOp::ConditionalBranch {
1034 cond_value,
1035 true_block,
1036 false_block,
1037 } => {
1038 replace(cond_value);
1039 true_block.args.iter_mut().for_each(replace);
1040 false_block.args.iter_mut().for_each(replace);
1041 }
1042 InstOp::ContractCall {
1043 params,
1044 coins,
1045 asset_id,
1046 gas,
1047 ..
1048 } => {
1049 replace(params);
1050 replace(coins);
1051 replace(asset_id);
1052 replace(gas);
1053 }
1054 InstOp::GetLocal(_) => (),
1055 InstOp::GetGlobal(_) => (),
1056 InstOp::GetConfig(_, _) => (),
1057 InstOp::GetStorageKey(_) => (),
1058 InstOp::GetElemPtr {
1059 base,
1060 elem_ptr_ty: _,
1061 indices,
1062 } => {
1063 replace(base);
1064 indices.iter_mut().for_each(replace);
1065 }
1066 InstOp::Alloc { ty: _, count } => replace(count),
1067 InstOp::IntToPtr(value, _) => replace(value),
1068 InstOp::Load(ptr) => replace(ptr),
1069 InstOp::MemCopyBytes {
1070 dst_val_ptr,
1071 src_val_ptr,
1072 ..
1073 } => {
1074 replace(dst_val_ptr);
1075 replace(src_val_ptr);
1076 }
1077 InstOp::MemCopyVal {
1078 dst_val_ptr,
1079 src_val_ptr,
1080 } => {
1081 replace(dst_val_ptr);
1082 replace(src_val_ptr);
1083 }
1084 InstOp::MemClearVal { dst_val_ptr } => {
1085 replace(dst_val_ptr);
1086 }
1087 InstOp::Nop => (),
1088 InstOp::PtrToInt(value, _) => replace(value),
1089 InstOp::Ret(ret_val, _) => replace(ret_val),
1090 InstOp::Store {
1091 stored_val,
1092 dst_val_ptr,
1093 } => {
1094 replace(stored_val);
1095 replace(dst_val_ptr);
1096 }
1097
1098 InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
1099 FuelVmInstruction::Gtf { index, .. } => replace(index),
1100 FuelVmInstruction::Log {
1101 log_val, log_id, ..
1102 } => {
1103 replace(log_val);
1104 replace(log_id);
1105 }
1106 FuelVmInstruction::ReadRegister { .. } => (),
1107 FuelVmInstruction::Revert(revert_val) => replace(revert_val),
1108 FuelVmInstruction::JmpMem => (),
1109 FuelVmInstruction::Smo {
1110 recipient,
1111 message,
1112 message_size,
1113 coins,
1114 } => {
1115 replace(recipient);
1116 replace(message);
1117 replace(message_size);
1118 replace(coins);
1119 }
1120 FuelVmInstruction::StateClear {
1121 key,
1122 number_of_slots,
1123 } => {
1124 replace(key);
1125 replace(number_of_slots);
1126 }
1127 FuelVmInstruction::StateLoadQuadWord {
1128 load_val,
1129 key,
1130 number_of_slots,
1131 } => {
1132 replace(load_val);
1133 replace(key);
1134 replace(number_of_slots);
1135 }
1136 FuelVmInstruction::StateLoadWord(key) => {
1137 replace(key);
1138 }
1139 FuelVmInstruction::StateStoreQuadWord {
1140 stored_val,
1141 key,
1142 number_of_slots,
1143 } => {
1144 replace(key);
1145 replace(stored_val);
1146 replace(number_of_slots);
1147 }
1148 FuelVmInstruction::StateStoreWord { stored_val, key } => {
1149 replace(key);
1150 replace(stored_val);
1151 }
1152 FuelVmInstruction::WideUnaryOp { arg, result, .. } => {
1153 replace(arg);
1154 replace(result);
1155 }
1156 FuelVmInstruction::WideBinaryOp {
1157 arg1, arg2, result, ..
1158 } => {
1159 replace(arg1);
1160 replace(arg2);
1161 replace(result);
1162 }
1163 FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => {
1164 replace(arg1);
1165 replace(arg2);
1166 }
1167 FuelVmInstruction::WideModularOp {
1168 result,
1169 arg1,
1170 arg2,
1171 arg3,
1172 ..
1173 } => {
1174 replace(result);
1175 replace(arg1);
1176 replace(arg2);
1177 replace(arg3);
1178 }
1179 FuelVmInstruction::Retd { ptr, len } => {
1180 replace(ptr);
1181 replace(len);
1182 }
1183 },
1184 }
1185 }
1186
1187 pub fn may_have_side_effect(&self) -> bool {
1188 match self {
1189 InstOp::AsmBlock(asm, _) => !asm.body.is_empty(),
1190 InstOp::Call(..)
1191 | InstOp::ContractCall { .. }
1192 | InstOp::FuelVm(FuelVmInstruction::Log { .. })
1193 | InstOp::FuelVm(FuelVmInstruction::Smo { .. })
1194 | InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
1195 | InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
1196 | InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
1197 | InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. })
1198 | InstOp::FuelVm(FuelVmInstruction::Revert(..))
1199 | InstOp::FuelVm(FuelVmInstruction::JmpMem)
1200 | InstOp::FuelVm(FuelVmInstruction::Retd { .. })
1201 | InstOp::MemCopyBytes { .. }
1202 | InstOp::MemCopyVal { .. }
1203 | InstOp::MemClearVal { .. }
1204 | InstOp::Store { .. }
1205 | InstOp::Ret(..)
1206 | InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { .. })
1207 | InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { .. })
1208 | InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. })
1209 | InstOp::FuelVm(FuelVmInstruction::WideModularOp { .. }) => true,
1210
1211 InstOp::UnaryOp { .. }
1212 | InstOp::BinaryOp { .. }
1213 | InstOp::BitCast(..)
1214 | InstOp::Branch(_)
1215 | InstOp::CastPtr { .. }
1216 | InstOp::Cmp(..)
1217 | InstOp::ConditionalBranch { .. }
1218 | InstOp::FuelVm(FuelVmInstruction::Gtf { .. })
1219 | InstOp::FuelVm(FuelVmInstruction::ReadRegister(_))
1220 | InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_))
1221 | InstOp::GetElemPtr { .. }
1222 | InstOp::GetLocal(_)
1223 | InstOp::GetGlobal(_)
1224 | InstOp::GetConfig(_, _)
1225 | InstOp::GetStorageKey(_)
1226 | InstOp::IntToPtr(..)
1227 | InstOp::Load(_)
1228 | InstOp::Nop
1229 | InstOp::PtrToInt(..) => false,
1230
1231 InstOp::Alloc { .. } => false,
1236 }
1237 }
1238
1239 pub fn is_terminator(&self) -> bool {
1240 matches!(
1241 self,
1242 InstOp::Branch(_)
1243 | InstOp::ConditionalBranch { .. }
1244 | InstOp::Ret(..)
1245 | InstOp::FuelVm(
1246 FuelVmInstruction::Revert(..)
1247 | FuelVmInstruction::JmpMem
1248 | FuelVmInstruction::Retd { .. }
1249 )
1250 )
1251 }
1252}
1253
1254pub struct InstructionIterator {
1256 instructions: Vec<slotmap::DefaultKey>,
1257 next: usize,
1258 next_back: isize,
1259}
1260
1261impl InstructionIterator {
1262 pub fn new(context: &Context, block: &Block) -> Self {
1263 InstructionIterator {
1266 instructions: context.blocks[block.0]
1267 .instructions
1268 .iter()
1269 .map(|val| val.0)
1270 .collect(),
1271 next: 0,
1272 next_back: context.blocks[block.0].instructions.len() as isize - 1,
1273 }
1274 }
1275}
1276
1277impl Iterator for InstructionIterator {
1278 type Item = Value;
1279
1280 fn next(&mut self) -> Option<Value> {
1281 if self.next < self.instructions.len() {
1282 let idx = self.next;
1283 self.next += 1;
1284 Some(Value(self.instructions[idx]))
1285 } else {
1286 None
1287 }
1288 }
1289}
1290
1291impl DoubleEndedIterator for InstructionIterator {
1292 fn next_back(&mut self) -> Option<Value> {
1293 if self.next_back >= 0 {
1294 let idx = self.next_back;
1295 self.next_back -= 1;
1296 Some(Value(self.instructions[idx as usize]))
1297 } else {
1298 None
1299 }
1300 }
1301}
1302
1303pub enum InsertionPosition {
1305 Start,
1307 End,
1309 After(Value),
1311 Before(Value),
1313 At(usize),
1315}
1316
1317pub struct InstructionInserter<'a, 'eng> {
1319 context: &'a mut Context<'eng>,
1320 block: Block,
1321 position: InsertionPosition,
1322}
1323
1324macro_rules! insert_instruction {
1325 ($self: ident, $ctor: expr) => {{
1326 let instruction_val = Value::new_instruction($self.context, $self.block, $ctor);
1327 let pos = $self.get_position_index();
1328 let instructions = &mut $self.context.blocks[$self.block.0].instructions;
1329 instructions.insert(pos, instruction_val);
1330 instruction_val
1331 }};
1332}
1333
1334impl<'a, 'eng> InstructionInserter<'a, 'eng> {
1335 pub fn new(
1337 context: &'a mut Context<'eng>,
1338 block: Block,
1339 position: InsertionPosition,
1340 ) -> InstructionInserter<'a, 'eng> {
1341 InstructionInserter {
1342 context,
1343 block,
1344 position,
1345 }
1346 }
1347
1348 fn get_position_index(&self) -> usize {
1350 let instructions = &self.context.blocks[self.block.0].instructions;
1351 match self.position {
1352 InsertionPosition::Start => 0,
1353 InsertionPosition::End => instructions.len(),
1354 InsertionPosition::After(inst) => {
1355 instructions
1356 .iter()
1357 .position(|val| *val == inst)
1358 .expect("Provided position for insertion does not exist")
1359 + 1
1360 }
1361 InsertionPosition::Before(inst) => instructions
1362 .iter()
1363 .position(|val| *val == inst)
1364 .expect("Provided position for insertion does not exist"),
1365 InsertionPosition::At(pos) => pos,
1366 }
1367 }
1368
1369 pub fn insert_slice(&mut self, slice: &[Value]) {
1371 let pos = self.get_position_index();
1372 self.context.blocks[self.block.0]
1373 .instructions
1374 .splice(pos..pos, slice.iter().cloned());
1375 }
1376
1377 pub fn insert(&mut self, inst: Value) {
1379 let pos = self.get_position_index();
1380 self.context.blocks[self.block.0]
1381 .instructions
1382 .insert(pos, inst);
1383 }
1384
1385 pub fn asm_block(
1391 self,
1392 args: Vec<AsmArg>,
1393 body: Vec<AsmInstruction>,
1394 return_type: Type,
1395 return_name: Option<Ident>,
1396 ) -> Value {
1397 let asm = AsmBlock::new(
1398 args.iter().map(|arg| arg.name.clone()).collect(),
1399 body,
1400 return_type,
1401 return_name,
1402 );
1403 self.asm_block_from_asm(asm, args)
1404 }
1405
1406 pub fn asm_block_from_asm(self, asm: AsmBlock, args: Vec<AsmArg>) -> Value {
1407 insert_instruction!(self, InstOp::AsmBlock(asm, args))
1408 }
1409
1410 pub fn bitcast(self, value: Value, ty: Type) -> Value {
1411 insert_instruction!(self, InstOp::BitCast(value, ty))
1412 }
1413
1414 pub fn unary_op(self, op: UnaryOpKind, arg: Value) -> Value {
1415 insert_instruction!(self, InstOp::UnaryOp { op, arg })
1416 }
1417
1418 pub fn wide_unary_op(self, op: UnaryOpKind, arg: Value, result: Value) -> Value {
1419 insert_instruction!(
1420 self,
1421 InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { op, arg, result })
1422 )
1423 }
1424
1425 pub fn wide_binary_op(
1426 self,
1427 op: BinaryOpKind,
1428 arg1: Value,
1429 arg2: Value,
1430 result: Value,
1431 ) -> Value {
1432 insert_instruction!(
1433 self,
1434 InstOp::FuelVm(FuelVmInstruction::WideBinaryOp {
1435 op,
1436 arg1,
1437 arg2,
1438 result
1439 })
1440 )
1441 }
1442
1443 pub fn wide_modular_op(
1444 self,
1445 op: BinaryOpKind,
1446 result: Value,
1447 arg1: Value,
1448 arg2: Value,
1449 arg3: Value,
1450 ) -> Value {
1451 insert_instruction!(
1452 self,
1453 InstOp::FuelVm(FuelVmInstruction::WideModularOp {
1454 op,
1455 result,
1456 arg1,
1457 arg2,
1458 arg3,
1459 })
1460 )
1461 }
1462
1463 pub fn wide_cmp_op(self, op: Predicate, arg1: Value, arg2: Value) -> Value {
1464 insert_instruction!(
1465 self,
1466 InstOp::FuelVm(FuelVmInstruction::WideCmpOp { op, arg1, arg2 })
1467 )
1468 }
1469
1470 pub fn binary_op(self, op: BinaryOpKind, arg1: Value, arg2: Value) -> Value {
1471 insert_instruction!(self, InstOp::BinaryOp { op, arg1, arg2 })
1472 }
1473
1474 pub fn branch(self, to_block: Block, dest_params: Vec<Value>) -> Value {
1475 let br_val = Value::new_instruction(
1476 self.context,
1477 self.block,
1478 InstOp::Branch(BranchToWithArgs {
1479 block: to_block,
1480 args: dest_params,
1481 }),
1482 );
1483 to_block.add_pred(self.context, &self.block);
1484 self.context.blocks[self.block.0].instructions.push(br_val);
1485 br_val
1486 }
1487
1488 pub fn call(self, function: Function, args: &[Value]) -> Value {
1489 insert_instruction!(self, InstOp::Call(function, args.to_vec()))
1490 }
1491
1492 pub fn cast_ptr(self, val: Value, ty: Type) -> Value {
1493 insert_instruction!(self, InstOp::CastPtr(val, ty))
1494 }
1495
1496 pub fn cmp(self, pred: Predicate, lhs_value: Value, rhs_value: Value) -> Value {
1497 insert_instruction!(self, InstOp::Cmp(pred, lhs_value, rhs_value))
1498 }
1499
1500 pub fn conditional_branch(
1501 self,
1502 cond_value: Value,
1503 true_block: Block,
1504 false_block: Block,
1505 true_dest_params: Vec<Value>,
1506 false_dest_params: Vec<Value>,
1507 ) -> Value {
1508 let cbr_val = Value::new_instruction(
1509 self.context,
1510 self.block,
1511 InstOp::ConditionalBranch {
1512 cond_value,
1513 true_block: BranchToWithArgs {
1514 block: true_block,
1515 args: true_dest_params,
1516 },
1517 false_block: BranchToWithArgs {
1518 block: false_block,
1519 args: false_dest_params,
1520 },
1521 },
1522 );
1523 true_block.add_pred(self.context, &self.block);
1524 false_block.add_pred(self.context, &self.block);
1525 self.context.blocks[self.block.0].instructions.push(cbr_val);
1526 cbr_val
1527 }
1528
1529 pub fn contract_call(
1530 self,
1531 return_type: Type,
1532 name: Option<String>,
1533 params: Value,
1534 coins: Value, asset_id: Value, gas: Value, ) -> Value {
1538 insert_instruction!(
1539 self,
1540 InstOp::ContractCall {
1541 return_type,
1542 name,
1543 params,
1544 coins,
1545 asset_id,
1546 gas,
1547 }
1548 )
1549 }
1550
1551 pub fn gtf(self, index: Value, tx_field_id: u64) -> Value {
1552 insert_instruction!(
1553 self,
1554 InstOp::FuelVm(FuelVmInstruction::Gtf { index, tx_field_id })
1555 )
1556 }
1557
1558 pub fn get_elem_ptr(self, base: Value, elem_ty: Type, indices: Vec<Value>) -> Value {
1561 let elem_ptr_ty = Type::new_typed_pointer(self.context, elem_ty);
1562 insert_instruction!(
1563 self,
1564 InstOp::GetElemPtr {
1565 base,
1566 elem_ptr_ty,
1567 indices
1568 }
1569 )
1570 }
1571
1572 pub fn get_elem_ptr_with_idx(self, base: Value, elem_ty: Type, index: u64) -> Value {
1573 let idx_val = ConstantContent::get_uint(self.context, 64, index);
1574 self.get_elem_ptr(base, elem_ty, vec![idx_val])
1575 }
1576
1577 pub fn get_elem_ptr_with_idcs(self, base: Value, elem_ty: Type, indices: &[u64]) -> Value {
1578 let idx_vals = indices
1579 .iter()
1580 .map(|idx| ConstantContent::get_uint(self.context, 64, *idx))
1581 .collect();
1582 self.get_elem_ptr(base, elem_ty, idx_vals)
1583 }
1584
1585 pub fn get_local(self, local_var: LocalVar) -> Value {
1586 insert_instruction!(self, InstOp::GetLocal(local_var))
1587 }
1588
1589 pub fn get_global(self, global_var: GlobalVar) -> Value {
1590 insert_instruction!(self, InstOp::GetGlobal(global_var))
1591 }
1592
1593 pub fn get_config(self, module: Module, name: String) -> Value {
1594 insert_instruction!(self, InstOp::GetConfig(module, name))
1595 }
1596
1597 pub fn alloc(self, ty: Type, count: Value) -> Value {
1598 insert_instruction!(self, InstOp::Alloc { ty, count })
1599 }
1600
1601 pub fn get_storage_key(self, storage_key: StorageKey) -> Value {
1602 insert_instruction!(self, InstOp::GetStorageKey(storage_key))
1603 }
1604
1605 pub fn int_to_ptr(self, value: Value, ty: Type) -> Value {
1606 insert_instruction!(self, InstOp::IntToPtr(value, ty))
1607 }
1608
1609 pub fn load(self, src_val: Value) -> Value {
1610 insert_instruction!(self, InstOp::Load(src_val))
1611 }
1612
1613 pub fn log(
1614 self,
1615 log_val: Value,
1616 log_ty: Type,
1617 log_id: Value,
1618 log_data: Option<LogEventData>,
1619 ) -> Value {
1620 insert_instruction!(
1621 self,
1622 InstOp::FuelVm(FuelVmInstruction::Log {
1623 log_val,
1624 log_ty,
1625 log_id,
1626 log_data
1627 })
1628 )
1629 }
1630
1631 pub fn mem_copy_bytes(self, dst_val_ptr: Value, src_val_ptr: Value, byte_len: u64) -> Value {
1632 insert_instruction!(
1633 self,
1634 InstOp::MemCopyBytes {
1635 dst_val_ptr,
1636 src_val_ptr,
1637 byte_len
1638 }
1639 )
1640 }
1641
1642 pub fn mem_copy_val(self, dst_val_ptr: Value, src_val_ptr: Value) -> Value {
1643 insert_instruction!(
1644 self,
1645 InstOp::MemCopyVal {
1646 dst_val_ptr,
1647 src_val_ptr,
1648 }
1649 )
1650 }
1651
1652 pub fn nop(self) -> Value {
1653 insert_instruction!(self, InstOp::Nop)
1654 }
1655
1656 pub fn ptr_to_int(self, value: Value, ty: Type) -> Value {
1657 insert_instruction!(self, InstOp::PtrToInt(value, ty))
1658 }
1659
1660 pub fn read_register(self, reg: Register) -> Value {
1661 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::ReadRegister(reg)))
1662 }
1663
1664 pub fn ret(self, value: Value, ty: Type) -> Value {
1665 insert_instruction!(self, InstOp::Ret(value, ty))
1666 }
1667
1668 pub fn retd(self, ptr: Value, len: Value) -> Value {
1669 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::Retd { ptr, len }))
1670 }
1671
1672 pub fn revert(self, value: Value) -> Value {
1673 let revert_val = Value::new_instruction(
1674 self.context,
1675 self.block,
1676 InstOp::FuelVm(FuelVmInstruction::Revert(value)),
1677 );
1678 self.context.blocks[self.block.0]
1679 .instructions
1680 .push(revert_val);
1681 revert_val
1682 }
1683
1684 pub fn jmp_mem(self) -> Value {
1685 let ldc_exec = Value::new_instruction(
1686 self.context,
1687 self.block,
1688 InstOp::FuelVm(FuelVmInstruction::JmpMem),
1689 );
1690 self.context.blocks[self.block.0]
1691 .instructions
1692 .push(ldc_exec);
1693 ldc_exec
1694 }
1695
1696 pub fn smo(self, recipient: Value, message: Value, message_size: Value, coins: Value) -> Value {
1697 insert_instruction!(
1698 self,
1699 InstOp::FuelVm(FuelVmInstruction::Smo {
1700 recipient,
1701 message,
1702 message_size,
1703 coins,
1704 })
1705 )
1706 }
1707
1708 pub fn state_clear(self, key: Value, number_of_slots: Value) -> Value {
1709 insert_instruction!(
1710 self,
1711 InstOp::FuelVm(FuelVmInstruction::StateClear {
1712 key,
1713 number_of_slots
1714 })
1715 )
1716 }
1717
1718 pub fn state_load_quad_word(
1719 self,
1720 load_val: Value,
1721 key: Value,
1722 number_of_slots: Value,
1723 ) -> Value {
1724 insert_instruction!(
1725 self,
1726 InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord {
1727 load_val,
1728 key,
1729 number_of_slots
1730 })
1731 )
1732 }
1733
1734 pub fn state_load_word(self, key: Value) -> Value {
1735 insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::StateLoadWord(key)))
1736 }
1737
1738 pub fn state_store_quad_word(
1739 self,
1740 stored_val: Value,
1741 key: Value,
1742 number_of_slots: Value,
1743 ) -> Value {
1744 insert_instruction!(
1745 self,
1746 InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord {
1747 stored_val,
1748 key,
1749 number_of_slots
1750 })
1751 )
1752 }
1753
1754 pub fn state_store_word(self, stored_val: Value, key: Value) -> Value {
1755 insert_instruction!(
1756 self,
1757 InstOp::FuelVm(FuelVmInstruction::StateStoreWord { stored_val, key })
1758 )
1759 }
1760
1761 pub fn store(self, dst_val_ptr: Value, stored_val: Value) -> Value {
1762 insert_instruction!(
1763 self,
1764 InstOp::Store {
1765 dst_val_ptr,
1766 stored_val,
1767 }
1768 )
1769 }
1770
1771 pub fn mem_clear_val(self, dst_val_ptr: Value) -> Value {
1772 insert_instruction!(self, InstOp::MemClearVal { dst_val_ptr })
1773 }
1774}