use miden_air::trace::decoder::NUM_USER_OP_HELPERS;
use miden_core::{Felt, FieldElement, ONE, ZERO};
use crate::{
ErrorContext, ExecutionError,
fast::Tracer,
operations::utils::assert_binary,
processor::{OperationHelperRegisters, Processor, StackInterface, SystemInterface},
};
#[inline(always)]
pub(super) fn op_add<P: Processor>(processor: &mut P, tracer: &mut impl Tracer) {
pop2_applyfn_push(processor, |a, b| Ok(a + b), tracer).unwrap()
}
#[inline(always)]
pub(super) fn op_neg<P: Processor>(processor: &mut P) {
let element = processor.stack().get(0);
processor.stack().set(0, -element);
}
#[inline(always)]
pub(super) fn op_mul<P: Processor>(processor: &mut P, tracer: &mut impl Tracer) {
pop2_applyfn_push(processor, |a, b| Ok(a * b), tracer).unwrap();
}
#[inline(always)]
pub(super) fn op_inv<P: Processor>(
processor: &mut P,
err_ctx: &impl ErrorContext,
) -> Result<(), ExecutionError> {
let top = processor.stack().get_mut(0);
if (*top) == ZERO {
return Err(ExecutionError::divide_by_zero(processor.system().clk(), err_ctx));
}
*top = top.inv();
Ok(())
}
#[inline(always)]
pub(super) fn op_incr<P: Processor>(processor: &mut P) {
*processor.stack().get_mut(0) += ONE;
}
#[inline(always)]
pub(super) fn op_and<P: Processor>(
processor: &mut P,
err_ctx: &impl ErrorContext,
tracer: &mut impl Tracer,
) -> Result<(), ExecutionError> {
pop2_applyfn_push(
processor,
|a, b| {
assert_binary(b, err_ctx)?;
assert_binary(a, err_ctx)?;
if a == ONE && b == ONE { Ok(ONE) } else { Ok(ZERO) }
},
tracer,
)
}
#[inline(always)]
pub(super) fn op_or<P: Processor>(
processor: &mut P,
err_ctx: &impl ErrorContext,
tracer: &mut impl Tracer,
) -> Result<(), ExecutionError> {
pop2_applyfn_push(
processor,
|a, b| {
assert_binary(b, err_ctx)?;
assert_binary(a, err_ctx)?;
if a == ONE || b == ONE { Ok(ONE) } else { Ok(ZERO) }
},
tracer,
)
}
#[inline(always)]
pub(super) fn op_not<P: Processor>(
processor: &mut P,
err_ctx: &impl ErrorContext,
) -> Result<(), ExecutionError> {
let top = processor.stack().get_mut(0);
if *top == ZERO {
*top = ONE;
} else if *top == ONE {
*top = ZERO;
} else {
return Err(ExecutionError::not_binary_value_op(*top, err_ctx));
}
Ok(())
}
#[inline(always)]
pub(super) fn op_eq<P: Processor>(
processor: &mut P,
tracer: &mut impl Tracer,
) -> [Felt; NUM_USER_OP_HELPERS] {
let b = processor.stack().get(0);
let a = processor.stack().get(1);
pop2_applyfn_push(processor, |a, b| if a == b { Ok(ONE) } else { Ok(ZERO) }, tracer).unwrap();
P::HelperRegisters::op_eq_registers(a, b)
}
#[inline(always)]
pub(super) fn op_eqz<P: Processor>(processor: &mut P) -> [Felt; NUM_USER_OP_HELPERS] {
let top = processor.stack().get_mut(0);
let old_top = *top;
if old_top == ZERO {
*top = ONE;
} else {
*top = ZERO;
};
P::HelperRegisters::op_eqz_registers(old_top)
}
#[inline(always)]
pub(super) fn op_expacc<P: Processor>(processor: &mut P) -> [Felt; NUM_USER_OP_HELPERS] {
let old_base = processor.stack().get(1);
let old_acc = processor.stack().get(2);
let old_exp_int = processor.stack().get(3).as_int();
let new_exp = Felt::new(old_exp_int >> 1);
let exp_lsb = old_exp_int & 1;
let acc_update_val = if exp_lsb == 1 { old_base } else { ONE };
let new_acc = old_acc * acc_update_val;
let new_base = old_base * old_base;
processor.stack().set(0, Felt::new(exp_lsb));
processor.stack().set(1, new_base);
processor.stack().set(2, new_acc);
processor.stack().set(3, new_exp);
P::HelperRegisters::op_expacc_registers(acc_update_val)
}
#[inline(always)]
pub(super) fn op_ext2mul<P: Processor>(processor: &mut P) {
const TWO: Felt = Felt::new(2);
let [a0, a1, b0, b1] = processor.stack().get_word(0).into();
let b0_times_a0 = b0 * a0;
processor.stack().set(2, (b0 + b1) * (a1 + a0) - b0_times_a0);
processor.stack().set(3, b0_times_a0 - TWO * b1 * a1);
}
#[inline(always)]
fn pop2_applyfn_push<P: Processor>(
processor: &mut P,
f: impl FnOnce(Felt, Felt) -> Result<Felt, ExecutionError>,
tracer: &mut impl Tracer,
) -> Result<(), ExecutionError> {
let b = processor.stack().get(0);
let a = processor.stack().get(1);
processor.stack().decrement_size(tracer);
processor.stack().set(0, f(a, b)?);
Ok(())
}