use super::{
ExecutableTransaction,
Interpreter,
internal::inc_pc,
is_unsafe_math,
is_wrapping,
};
use crate::{
constraints::reg_key::*,
error::SimpleResult,
};
use fuel_asm::{
PanicReason,
RegId,
};
use fuel_types::Word;
mod muldiv;
mod narrowint;
mod wideint;
impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
where
Tx: ExecutableTransaction,
{
pub(crate) fn alu_capture_overflow<F, B, C>(
&mut self,
ra: RegId,
f: F,
b: B,
c: C,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> (u128, bool),
{
let (
SystemRegisters {
flag, of, err, pc, ..
},
mut w,
) = split_registers(&mut self.registers);
let dest = &mut w[ra.try_into()?];
let common = AluCommonReg { of, err, pc };
alu_capture_overflow(dest, flag.as_ref(), common, f, b, c)
}
pub(crate) fn alu_boolean_overflow<F, B, C>(
&mut self,
ra: RegId,
f: F,
b: B,
c: C,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> (Word, bool),
{
let (
SystemRegisters {
flag, of, err, pc, ..
},
mut w,
) = split_registers(&mut self.registers);
let dest = &mut w[ra.try_into()?];
let common = AluCommonReg { of, err, pc };
alu_boolean_overflow(dest, flag.as_ref(), common, f, b, c)
}
pub(crate) fn alu_error<F, B, C>(
&mut self,
ra: RegId,
f: F,
b: B,
c: C,
err_bool: bool,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> Word,
{
let (
SystemRegisters {
flag, of, err, pc, ..
},
mut w,
) = split_registers(&mut self.registers);
let dest = &mut w[ra.try_into()?];
let common = AluCommonReg { of, err, pc };
alu_error(dest, flag.as_ref(), common, f, b, c, err_bool)
}
pub(crate) fn alu_set(&mut self, ra: RegId, b: Word) -> SimpleResult<()> {
let (SystemRegisters { of, err, pc, .. }, mut w) =
split_registers(&mut self.registers);
let dest = &mut w[ra.try_into()?];
let common = AluCommonReg { of, err, pc };
alu_set(dest, common, b);
Ok(())
}
pub(crate) fn alu_clear(&mut self) -> SimpleResult<()> {
let (SystemRegisters { of, err, pc, .. }, _) =
split_registers(&mut self.registers);
let common = AluCommonReg { of, err, pc };
alu_clear(common);
Ok(())
}
}
pub(crate) fn exp(b: Word, c: Word) -> (Word, bool) {
if let Ok(expo) = u32::try_from(c) {
Word::overflowing_pow(b, expo)
} else if b < 2 {
(b, false)
} else {
(0, true)
}
}
pub(crate) struct AluCommonReg<'a> {
pub of: RegMut<'a, OF>,
pub err: RegMut<'a, ERR>,
pub pc: RegMut<'a, PC>,
}
pub(crate) fn alu_capture_overflow<F, B, C>(
dest: &mut Word,
flag: Reg<FLAG>,
mut common: AluCommonReg,
f: F,
b: B,
c: C,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> (u128, bool),
{
let (result, _overflow) = f(b, c);
if result > Word::MAX as u128 && !is_wrapping(flag) {
return Err(PanicReason::ArithmeticOverflow.into())
}
*common.of = (result >> 64) as u64;
*common.err = 0;
*dest = u64::try_from(result & Word::MAX as u128)
.expect("We already truncated the result");
inc_pc(common.pc);
Ok(())
}
pub(crate) fn alu_boolean_overflow<F, B, C>(
dest: &mut Word,
flag: Reg<FLAG>,
mut common: AluCommonReg,
f: F,
b: B,
c: C,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> (Word, bool),
{
let (result, overflow) = f(b, c);
if overflow && !is_wrapping(flag) {
return Err(PanicReason::ArithmeticOverflow.into())
}
*common.of = overflow as Word;
*common.err = 0;
*dest = if overflow { 0 } else { result };
inc_pc(common.pc);
Ok(())
}
pub(crate) fn alu_error<F, B, C>(
dest: &mut Word,
flag: Reg<FLAG>,
mut common: AluCommonReg,
f: F,
b: B,
c: C,
err_bool: bool,
) -> SimpleResult<()>
where
F: FnOnce(B, C) -> Word,
{
if err_bool && !is_unsafe_math(flag) {
return Err(PanicReason::ArithmeticError.into())
}
*common.of = 0;
*common.err = err_bool as Word;
*dest = if err_bool { 0 } else { f(b, c) };
inc_pc(common.pc);
Ok(())
}
pub(crate) fn alu_set(dest: &mut Word, mut common: AluCommonReg, b: Word) {
*common.of = 0;
*common.err = 0;
*dest = b;
inc_pc(common.pc)
}
pub(crate) fn alu_clear(mut common: AluCommonReg) {
*common.of = 0;
*common.err = 0;
inc_pc(common.pc)
}