use rustc_hash::FxHashMap;
use sway_types::Ident;
use crate::{
asm::{AsmArg, AsmBlock},
block::Block,
context::Context,
function::Function,
irtype::Type,
local_var::LocalVar,
pretty::DebugWithContext,
value::{Value, ValueDatum},
AsmInstruction, Constant, Module,
};
#[derive(Debug, Clone, DebugWithContext)]
pub struct BranchToWithArgs {
pub block: Block,
pub args: Vec<Value>,
}
#[derive(Debug, Clone, DebugWithContext)]
pub struct Instruction {
pub parent: Block,
pub op: InstOp,
}
impl Instruction {
pub fn get_type(&self, context: &Context) -> Option<Type> {
self.op.get_type(context)
}
pub fn replace_values(&mut self, replace_map: &FxHashMap<Value, Value>) {
self.op.replace_values(replace_map)
}
}
#[derive(Debug, Clone, DebugWithContext)]
pub enum InstOp {
AsmBlock(AsmBlock, Vec<AsmArg>),
UnaryOp { op: UnaryOpKind, arg: Value },
BinaryOp {
op: BinaryOpKind,
arg1: Value,
arg2: Value,
},
BitCast(Value, Type),
Branch(BranchToWithArgs),
Call(Function, Vec<Value>),
CastPtr(Value, Type),
Cmp(Predicate, Value, Value),
ConditionalBranch {
cond_value: Value,
true_block: BranchToWithArgs,
false_block: BranchToWithArgs,
},
ContractCall {
return_type: Type,
name: Option<String>,
params: Value,
coins: Value,
asset_id: Value,
gas: Value,
},
FuelVm(FuelVmInstruction),
GetLocal(LocalVar),
GetConfig(Module, String),
GetElemPtr {
base: Value,
elem_ptr_ty: Type,
indices: Vec<Value>,
},
IntToPtr(Value, Type),
Load(Value),
MemCopyBytes {
dst_val_ptr: Value,
src_val_ptr: Value,
byte_len: u64,
},
MemCopyVal {
dst_val_ptr: Value,
src_val_ptr: Value,
},
Nop,
PtrToInt(Value, Type),
Ret(Value, Type),
Store {
dst_val_ptr: Value,
stored_val: Value,
},
}
#[derive(Debug, Clone, DebugWithContext)]
pub enum FuelVmInstruction {
Gtf {
index: Value,
tx_field_id: u64,
},
Log {
log_val: Value,
log_ty: Type,
log_id: Value,
},
ReadRegister(Register),
Revert(Value),
Smo {
recipient: Value,
message: Value,
message_size: Value,
coins: Value,
},
StateClear {
key: Value,
number_of_slots: Value,
},
StateLoadQuadWord {
load_val: Value,
key: Value,
number_of_slots: Value,
},
StateLoadWord(Value),
StateStoreQuadWord {
stored_val: Value,
key: Value,
number_of_slots: Value,
},
StateStoreWord {
stored_val: Value,
key: Value,
},
WideUnaryOp {
op: UnaryOpKind,
result: Value,
arg: Value,
},
WideBinaryOp {
op: BinaryOpKind,
result: Value,
arg1: Value,
arg2: Value,
},
WideModularOp {
op: BinaryOpKind,
result: Value,
arg1: Value,
arg2: Value,
arg3: Value,
},
WideCmpOp {
op: Predicate,
arg1: Value,
arg2: Value,
},
JmpMem,
Retd {
ptr: Value,
len: Value,
},
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Predicate {
Equal,
LessThan,
GreaterThan,
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum UnaryOpKind {
Not,
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum BinaryOpKind {
Add,
Sub,
Mul,
Div,
And,
Or,
Xor,
Mod,
Rsh,
Lsh,
}
#[derive(Debug, Clone, Copy, Hash)]
pub enum Register {
Of,
Pc,
Ssp,
Sp,
Fp,
Hp,
Error,
Ggas,
Cgas,
Bal,
Is,
Ret,
Retl,
Flag,
}
impl InstOp {
pub fn get_type(&self, context: &Context) -> Option<Type> {
match self {
InstOp::AsmBlock(asm_block, _) => Some(asm_block.return_type),
InstOp::UnaryOp { arg, .. } => arg.get_type(context),
InstOp::BinaryOp { arg1, .. } => arg1.get_type(context),
InstOp::BitCast(_, ty) => Some(*ty),
InstOp::Call(function, _) => Some(context.functions[function.0].return_type),
InstOp::CastPtr(_val, ty) => Some(*ty),
InstOp::Cmp(..) => Some(Type::get_bool(context)),
InstOp::ContractCall { return_type, .. } => Some(*return_type),
InstOp::FuelVm(FuelVmInstruction::Gtf { .. }) => Some(Type::get_uint64(context)),
InstOp::FuelVm(FuelVmInstruction::Log { .. }) => Some(Type::get_unit(context)),
InstOp::FuelVm(FuelVmInstruction::ReadRegister(_)) => Some(Type::get_uint64(context)),
InstOp::FuelVm(FuelVmInstruction::Smo { .. }) => Some(Type::get_unit(context)),
InstOp::Load(ptr_val) => match &context.values[ptr_val.0].value {
ValueDatum::Argument(arg) => arg.ty.get_pointee_type(context),
ValueDatum::Constant(cons) => cons.ty.get_pointee_type(context),
ValueDatum::Instruction(ins) => ins
.get_type(context)
.and_then(|ty| ty.get_pointee_type(context)),
},
InstOp::GetElemPtr { elem_ptr_ty, .. } => Some(*elem_ptr_ty),
InstOp::GetLocal(local_var) => Some(local_var.get_type(context)),
InstOp::GetConfig(module, name) => Some(match module.get_config(context, name)? {
crate::ConfigContent::V0 { ptr_ty, .. } => *ptr_ty,
crate::ConfigContent::V1 { ptr_ty, .. } => *ptr_ty,
}),
InstOp::IntToPtr(_, ptr_ty) => Some(*ptr_ty),
InstOp::PtrToInt(_, int_ty) => Some(*int_ty),
InstOp::Branch(_)
| InstOp::ConditionalBranch { .. }
| InstOp::FuelVm(
FuelVmInstruction::Revert(..)
| FuelVmInstruction::JmpMem
| FuelVmInstruction::Retd { .. },
)
| InstOp::Ret(..) => None,
InstOp::Nop => None,
InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_)) => Some(Type::get_uint64(context)),
InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
| InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. }) => {
Some(Type::get_bool(context))
}
InstOp::MemCopyBytes { .. } | InstOp::MemCopyVal { .. } | InstOp::Store { .. } => {
Some(Type::get_unit(context))
}
InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { result, .. }) => {
result.get_type(context)
}
InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { result, .. }) => {
result.get_type(context)
}
InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. }) => Some(Type::get_bool(context)),
InstOp::FuelVm(FuelVmInstruction::WideModularOp { result, .. }) => {
result.get_type(context)
}
}
}
pub fn get_operands(&self) -> Vec<Value> {
match self {
InstOp::AsmBlock(_, args) => args.iter().filter_map(|aa| aa.initializer).collect(),
InstOp::BitCast(v, _) => vec![*v],
InstOp::UnaryOp { op: _, arg } => vec![*arg],
InstOp::BinaryOp { op: _, arg1, arg2 } => vec![*arg1, *arg2],
InstOp::Branch(BranchToWithArgs { args, .. }) => args.clone(),
InstOp::Call(_, vs) => vs.clone(),
InstOp::CastPtr(val, _ty) => vec![*val],
InstOp::Cmp(_, lhs, rhs) => vec![*lhs, *rhs],
InstOp::ConditionalBranch {
cond_value,
true_block,
false_block,
} => {
let mut v = vec![*cond_value];
v.extend_from_slice(&true_block.args);
v.extend_from_slice(&false_block.args);
v
}
InstOp::ContractCall {
return_type: _,
name: _,
params,
coins,
asset_id,
gas,
} => vec![*params, *coins, *asset_id, *gas],
InstOp::GetElemPtr {
base,
elem_ptr_ty: _,
indices,
} => {
let mut vals = indices.clone();
vals.push(*base);
vals
}
InstOp::GetLocal(_local_var) => {
vec![]
}
InstOp::GetConfig(_, _) => {
vec![]
}
InstOp::IntToPtr(v, _) => vec![*v],
InstOp::Load(v) => vec![*v],
InstOp::MemCopyBytes {
dst_val_ptr,
src_val_ptr,
byte_len: _,
} => {
vec![*dst_val_ptr, *src_val_ptr]
}
InstOp::MemCopyVal {
dst_val_ptr,
src_val_ptr,
} => {
vec![*dst_val_ptr, *src_val_ptr]
}
InstOp::Nop => vec![],
InstOp::PtrToInt(v, _) => vec![*v],
InstOp::Ret(v, _) => vec![*v],
InstOp::Store {
dst_val_ptr,
stored_val,
} => {
vec![*dst_val_ptr, *stored_val]
}
InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
FuelVmInstruction::Gtf {
index,
tx_field_id: _,
} => vec![*index],
FuelVmInstruction::Log {
log_val, log_id, ..
} => vec![*log_val, *log_id],
FuelVmInstruction::ReadRegister(_) => vec![],
FuelVmInstruction::Revert(v) => vec![*v],
FuelVmInstruction::JmpMem => vec![],
FuelVmInstruction::Smo {
recipient,
message,
message_size,
coins,
} => vec![*recipient, *message, *message_size, *coins],
FuelVmInstruction::StateClear {
key,
number_of_slots,
} => vec![*key, *number_of_slots],
FuelVmInstruction::StateLoadQuadWord {
load_val,
key,
number_of_slots,
} => vec![*load_val, *key, *number_of_slots],
FuelVmInstruction::StateLoadWord(key) => vec![*key],
FuelVmInstruction::StateStoreQuadWord {
stored_val,
key,
number_of_slots,
} => {
vec![*stored_val, *key, *number_of_slots]
}
FuelVmInstruction::StateStoreWord { stored_val, key } => vec![*stored_val, *key],
FuelVmInstruction::WideUnaryOp { arg, result, .. } => vec![*result, *arg],
FuelVmInstruction::WideBinaryOp {
arg1, arg2, result, ..
} => vec![*result, *arg1, *arg2],
FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => vec![*arg1, *arg2],
FuelVmInstruction::WideModularOp {
result,
arg1,
arg2,
arg3,
..
} => vec![*result, *arg1, *arg2, *arg3],
FuelVmInstruction::Retd { ptr, len } => {
vec![*ptr, *len]
}
},
}
}
pub fn replace_values(&mut self, replace_map: &FxHashMap<Value, Value>) {
let replace = |val: &mut Value| {
while let Some(new_val) = replace_map.get(val) {
*val = *new_val;
}
};
match self {
InstOp::AsmBlock(_, args) => args
.iter_mut()
.for_each(|asm_arg| asm_arg.initializer.iter_mut().for_each(replace)),
InstOp::BitCast(value, _) => replace(value),
InstOp::UnaryOp { op: _, arg } => {
replace(arg);
}
InstOp::BinaryOp { op: _, arg1, arg2 } => {
replace(arg1);
replace(arg2);
}
InstOp::Branch(block) => {
block.args.iter_mut().for_each(replace);
}
InstOp::Call(_, args) => args.iter_mut().for_each(replace),
InstOp::CastPtr(val, _ty) => replace(val),
InstOp::Cmp(_, lhs_val, rhs_val) => {
replace(lhs_val);
replace(rhs_val);
}
InstOp::ConditionalBranch {
cond_value,
true_block,
false_block,
} => {
replace(cond_value);
true_block.args.iter_mut().for_each(replace);
false_block.args.iter_mut().for_each(replace);
}
InstOp::ContractCall {
params,
coins,
asset_id,
gas,
..
} => {
replace(params);
replace(coins);
replace(asset_id);
replace(gas);
}
InstOp::GetLocal(_) => (),
InstOp::GetConfig(_, _) => (),
InstOp::GetElemPtr {
base,
elem_ptr_ty: _,
indices,
} => {
replace(base);
indices.iter_mut().for_each(replace);
}
InstOp::IntToPtr(value, _) => replace(value),
InstOp::Load(ptr) => replace(ptr),
InstOp::MemCopyBytes {
dst_val_ptr,
src_val_ptr,
..
} => {
replace(dst_val_ptr);
replace(src_val_ptr);
}
InstOp::MemCopyVal {
dst_val_ptr,
src_val_ptr,
} => {
replace(dst_val_ptr);
replace(src_val_ptr);
}
InstOp::Nop => (),
InstOp::PtrToInt(value, _) => replace(value),
InstOp::Ret(ret_val, _) => replace(ret_val),
InstOp::Store {
stored_val,
dst_val_ptr,
} => {
replace(stored_val);
replace(dst_val_ptr);
}
InstOp::FuelVm(fuel_vm_instr) => match fuel_vm_instr {
FuelVmInstruction::Gtf { index, .. } => replace(index),
FuelVmInstruction::Log {
log_val, log_id, ..
} => {
replace(log_val);
replace(log_id);
}
FuelVmInstruction::ReadRegister { .. } => (),
FuelVmInstruction::Revert(revert_val) => replace(revert_val),
FuelVmInstruction::JmpMem => (),
FuelVmInstruction::Smo {
recipient,
message,
message_size,
coins,
} => {
replace(recipient);
replace(message);
replace(message_size);
replace(coins);
}
FuelVmInstruction::StateClear {
key,
number_of_slots,
} => {
replace(key);
replace(number_of_slots);
}
FuelVmInstruction::StateLoadQuadWord {
load_val,
key,
number_of_slots,
} => {
replace(load_val);
replace(key);
replace(number_of_slots);
}
FuelVmInstruction::StateLoadWord(key) => {
replace(key);
}
FuelVmInstruction::StateStoreQuadWord {
stored_val,
key,
number_of_slots,
} => {
replace(key);
replace(stored_val);
replace(number_of_slots);
}
FuelVmInstruction::StateStoreWord { stored_val, key } => {
replace(key);
replace(stored_val);
}
FuelVmInstruction::WideUnaryOp { arg, result, .. } => {
replace(arg);
replace(result);
}
FuelVmInstruction::WideBinaryOp {
arg1, arg2, result, ..
} => {
replace(arg1);
replace(arg2);
replace(result);
}
FuelVmInstruction::WideCmpOp { arg1, arg2, .. } => {
replace(arg1);
replace(arg2);
}
FuelVmInstruction::WideModularOp {
result,
arg1,
arg2,
arg3,
..
} => {
replace(result);
replace(arg1);
replace(arg2);
replace(arg3);
}
FuelVmInstruction::Retd { ptr, len } => {
replace(ptr);
replace(len);
}
},
}
}
pub fn may_have_side_effect(&self) -> bool {
match self {
InstOp::AsmBlock(asm, _) => !asm.body.is_empty(),
InstOp::Call(..)
| InstOp::ContractCall { .. }
| InstOp::FuelVm(FuelVmInstruction::Log { .. })
| InstOp::FuelVm(FuelVmInstruction::Smo { .. })
| InstOp::FuelVm(FuelVmInstruction::StateClear { .. })
| InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord { .. })
| InstOp::FuelVm(FuelVmInstruction::StateStoreWord { .. })
| InstOp::FuelVm(FuelVmInstruction::Revert(..))
| InstOp::FuelVm(FuelVmInstruction::JmpMem)
| InstOp::FuelVm(FuelVmInstruction::Retd { .. })
| InstOp::MemCopyBytes { .. }
| InstOp::MemCopyVal { .. }
| InstOp::Store { .. }
| InstOp::Ret(..)
| InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { .. })
| InstOp::FuelVm(FuelVmInstruction::WideBinaryOp { .. })
| InstOp::FuelVm(FuelVmInstruction::WideCmpOp { .. })
| InstOp::FuelVm(FuelVmInstruction::WideModularOp { .. }) => true,
InstOp::UnaryOp { .. }
| InstOp::BinaryOp { .. }
| InstOp::BitCast(..)
| InstOp::Branch(_)
| InstOp::CastPtr { .. }
| InstOp::Cmp(..)
| InstOp::ConditionalBranch { .. }
| InstOp::FuelVm(FuelVmInstruction::Gtf { .. })
| InstOp::FuelVm(FuelVmInstruction::ReadRegister(_))
| InstOp::FuelVm(FuelVmInstruction::StateLoadWord(_))
| InstOp::GetElemPtr { .. }
| InstOp::GetLocal(_)
| InstOp::GetConfig(_, _)
| InstOp::IntToPtr(..)
| InstOp::Load(_)
| InstOp::Nop
| InstOp::PtrToInt(..) => false,
}
}
pub fn is_terminator(&self) -> bool {
matches!(
self,
InstOp::Branch(_)
| InstOp::ConditionalBranch { .. }
| InstOp::Ret(..)
| InstOp::FuelVm(
FuelVmInstruction::Revert(..)
| FuelVmInstruction::JmpMem
| FuelVmInstruction::Retd { .. }
)
)
}
}
pub struct InstructionIterator {
instructions: Vec<slotmap::DefaultKey>,
next: usize,
next_back: isize,
}
impl InstructionIterator {
pub fn new(context: &Context, block: &Block) -> Self {
InstructionIterator {
instructions: context.blocks[block.0]
.instructions
.iter()
.map(|val| val.0)
.collect(),
next: 0,
next_back: context.blocks[block.0].instructions.len() as isize - 1,
}
}
}
impl Iterator for InstructionIterator {
type Item = Value;
fn next(&mut self) -> Option<Value> {
if self.next < self.instructions.len() {
let idx = self.next;
self.next += 1;
Some(Value(self.instructions[idx]))
} else {
None
}
}
}
impl DoubleEndedIterator for InstructionIterator {
fn next_back(&mut self) -> Option<Value> {
if self.next_back >= 0 {
let idx = self.next_back;
self.next_back -= 1;
Some(Value(self.instructions[idx as usize]))
} else {
None
}
}
}
pub enum InsertionPosition {
Start,
End,
After(Value),
Before(Value),
At(usize),
}
pub struct InstructionInserter<'a, 'eng> {
context: &'a mut Context<'eng>,
block: Block,
position: InsertionPosition,
}
macro_rules! insert_instruction {
($self: ident, $ctor: expr) => {{
let instruction_val = Value::new_instruction($self.context, $self.block, $ctor);
let pos = $self.get_position_index();
let instructions = &mut $self.context.blocks[$self.block.0].instructions;
instructions.insert(pos, instruction_val);
instruction_val
}};
}
impl<'a, 'eng> InstructionInserter<'a, 'eng> {
pub fn new(
context: &'a mut Context<'eng>,
block: Block,
position: InsertionPosition,
) -> InstructionInserter<'a, 'eng> {
InstructionInserter {
context,
block,
position,
}
}
fn get_position_index(&self) -> usize {
let instructions = &self.context.blocks[self.block.0].instructions;
match self.position {
InsertionPosition::Start => 0,
InsertionPosition::End => instructions.len(),
InsertionPosition::After(inst) => {
instructions
.iter()
.position(|val| *val == inst)
.expect("Provided position for insertion does not exist")
+ 1
}
InsertionPosition::Before(inst) => instructions
.iter()
.position(|val| *val == inst)
.expect("Provided position for insertion does not exist"),
InsertionPosition::At(pos) => pos,
}
}
pub fn insert_slice(&mut self, slice: &[Value]) {
let pos = self.get_position_index();
self.context.blocks[self.block.0]
.instructions
.splice(pos..pos, slice.iter().cloned());
}
pub fn insert(&mut self, inst: Value) {
let pos = self.get_position_index();
self.context.blocks[self.block.0]
.instructions
.insert(pos, inst);
}
pub fn asm_block(
self,
args: Vec<AsmArg>,
body: Vec<AsmInstruction>,
return_type: Type,
return_name: Option<Ident>,
) -> Value {
let asm = AsmBlock::new(
args.iter().map(|arg| arg.name.clone()).collect(),
body,
return_type,
return_name,
);
self.asm_block_from_asm(asm, args)
}
pub fn asm_block_from_asm(self, asm: AsmBlock, args: Vec<AsmArg>) -> Value {
insert_instruction!(self, InstOp::AsmBlock(asm, args))
}
pub fn bitcast(self, value: Value, ty: Type) -> Value {
insert_instruction!(self, InstOp::BitCast(value, ty))
}
pub fn unary_op(self, op: UnaryOpKind, arg: Value) -> Value {
insert_instruction!(self, InstOp::UnaryOp { op, arg })
}
pub fn wide_unary_op(self, op: UnaryOpKind, arg: Value, result: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::WideUnaryOp { op, arg, result })
)
}
pub fn wide_binary_op(
self,
op: BinaryOpKind,
arg1: Value,
arg2: Value,
result: Value,
) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::WideBinaryOp {
op,
arg1,
arg2,
result
})
)
}
pub fn wide_modular_op(
self,
op: BinaryOpKind,
result: Value,
arg1: Value,
arg2: Value,
arg3: Value,
) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::WideModularOp {
op,
result,
arg1,
arg2,
arg3,
})
)
}
pub fn wide_cmp_op(self, op: Predicate, arg1: Value, arg2: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::WideCmpOp { op, arg1, arg2 })
)
}
pub fn binary_op(self, op: BinaryOpKind, arg1: Value, arg2: Value) -> Value {
insert_instruction!(self, InstOp::BinaryOp { op, arg1, arg2 })
}
pub fn branch(self, to_block: Block, dest_params: Vec<Value>) -> Value {
let br_val = Value::new_instruction(
self.context,
self.block,
InstOp::Branch(BranchToWithArgs {
block: to_block,
args: dest_params,
}),
);
to_block.add_pred(self.context, &self.block);
self.context.blocks[self.block.0].instructions.push(br_val);
br_val
}
pub fn call(self, function: Function, args: &[Value]) -> Value {
insert_instruction!(self, InstOp::Call(function, args.to_vec()))
}
pub fn cast_ptr(self, val: Value, ty: Type) -> Value {
insert_instruction!(self, InstOp::CastPtr(val, ty))
}
pub fn cmp(self, pred: Predicate, lhs_value: Value, rhs_value: Value) -> Value {
insert_instruction!(self, InstOp::Cmp(pred, lhs_value, rhs_value))
}
pub fn conditional_branch(
self,
cond_value: Value,
true_block: Block,
false_block: Block,
true_dest_params: Vec<Value>,
false_dest_params: Vec<Value>,
) -> Value {
let cbr_val = Value::new_instruction(
self.context,
self.block,
InstOp::ConditionalBranch {
cond_value,
true_block: BranchToWithArgs {
block: true_block,
args: true_dest_params,
},
false_block: BranchToWithArgs {
block: false_block,
args: false_dest_params,
},
},
);
true_block.add_pred(self.context, &self.block);
false_block.add_pred(self.context, &self.block);
self.context.blocks[self.block.0].instructions.push(cbr_val);
cbr_val
}
pub fn contract_call(
self,
return_type: Type,
name: Option<String>,
params: Value,
coins: Value, asset_id: Value, gas: Value, ) -> Value {
insert_instruction!(
self,
InstOp::ContractCall {
return_type,
name,
params,
coins,
asset_id,
gas,
}
)
}
pub fn gtf(self, index: Value, tx_field_id: u64) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::Gtf { index, tx_field_id })
)
}
pub fn get_elem_ptr(self, base: Value, elem_ty: Type, indices: Vec<Value>) -> Value {
let elem_ptr_ty = Type::new_ptr(self.context, elem_ty);
insert_instruction!(
self,
InstOp::GetElemPtr {
base,
elem_ptr_ty,
indices
}
)
}
pub fn get_elem_ptr_with_idx(self, base: Value, elem_ty: Type, index: u64) -> Value {
let idx_val = Constant::get_uint(self.context, 64, index);
self.get_elem_ptr(base, elem_ty, vec![idx_val])
}
pub fn get_elem_ptr_with_idcs(self, base: Value, elem_ty: Type, indices: &[u64]) -> Value {
let idx_vals = indices
.iter()
.map(|idx| Constant::get_uint(self.context, 64, *idx))
.collect();
self.get_elem_ptr(base, elem_ty, idx_vals)
}
pub fn get_local(self, local_var: LocalVar) -> Value {
insert_instruction!(self, InstOp::GetLocal(local_var))
}
pub fn get_config(self, module: Module, name: String) -> Value {
insert_instruction!(self, InstOp::GetConfig(module, name))
}
pub fn int_to_ptr(self, value: Value, ty: Type) -> Value {
insert_instruction!(self, InstOp::IntToPtr(value, ty))
}
pub fn load(self, src_val: Value) -> Value {
insert_instruction!(self, InstOp::Load(src_val))
}
pub fn log(self, log_val: Value, log_ty: Type, log_id: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::Log {
log_val,
log_ty,
log_id
})
)
}
pub fn mem_copy_bytes(self, dst_val_ptr: Value, src_val_ptr: Value, byte_len: u64) -> Value {
insert_instruction!(
self,
InstOp::MemCopyBytes {
dst_val_ptr,
src_val_ptr,
byte_len
}
)
}
pub fn mem_copy_val(self, dst_val_ptr: Value, src_val_ptr: Value) -> Value {
insert_instruction!(
self,
InstOp::MemCopyVal {
dst_val_ptr,
src_val_ptr,
}
)
}
pub fn nop(self) -> Value {
insert_instruction!(self, InstOp::Nop)
}
pub fn ptr_to_int(self, value: Value, ty: Type) -> Value {
insert_instruction!(self, InstOp::PtrToInt(value, ty))
}
pub fn read_register(self, reg: Register) -> Value {
insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::ReadRegister(reg)))
}
pub fn ret(self, value: Value, ty: Type) -> Value {
insert_instruction!(self, InstOp::Ret(value, ty))
}
pub fn retd(self, ptr: Value, len: Value) -> Value {
insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::Retd { ptr, len }))
}
pub fn revert(self, value: Value) -> Value {
let revert_val = Value::new_instruction(
self.context,
self.block,
InstOp::FuelVm(FuelVmInstruction::Revert(value)),
);
self.context.blocks[self.block.0]
.instructions
.push(revert_val);
revert_val
}
pub fn jmp_mem(self) -> Value {
let ldc_exec = Value::new_instruction(
self.context,
self.block,
InstOp::FuelVm(FuelVmInstruction::JmpMem),
);
self.context.blocks[self.block.0]
.instructions
.push(ldc_exec);
ldc_exec
}
pub fn smo(self, recipient: Value, message: Value, message_size: Value, coins: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::Smo {
recipient,
message,
message_size,
coins,
})
)
}
pub fn state_clear(self, key: Value, number_of_slots: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::StateClear {
key,
number_of_slots
})
)
}
pub fn state_load_quad_word(
self,
load_val: Value,
key: Value,
number_of_slots: Value,
) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::StateLoadQuadWord {
load_val,
key,
number_of_slots
})
)
}
pub fn state_load_word(self, key: Value) -> Value {
insert_instruction!(self, InstOp::FuelVm(FuelVmInstruction::StateLoadWord(key)))
}
pub fn state_store_quad_word(
self,
stored_val: Value,
key: Value,
number_of_slots: Value,
) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::StateStoreQuadWord {
stored_val,
key,
number_of_slots
})
)
}
pub fn state_store_word(self, stored_val: Value, key: Value) -> Value {
insert_instruction!(
self,
InstOp::FuelVm(FuelVmInstruction::StateStoreWord { stored_val, key })
)
}
pub fn store(self, dst_val_ptr: Value, stored_val: Value) -> Value {
insert_instruction!(
self,
InstOp::Store {
dst_val_ptr,
stored_val,
}
)
}
}