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