openvm_instructions/
instruction.rs

1use backtrace::Backtrace;
2use openvm_stark_backend::p3_field::Field;
3use serde::{Deserialize, Serialize};
4
5use crate::{utils::isize_to_field, LocalOpcode, PhantomDiscriminant, SystemOpcode, VmOpcode};
6
7/// Number of operands of an instruction.
8pub const NUM_OPERANDS: usize = 7;
9
10#[repr(C)]
11#[allow(clippy::too_many_arguments)]
12#[derive(Clone, Debug, PartialEq, Eq, derive_new::new, Serialize, Deserialize)]
13pub struct Instruction<F> {
14    pub opcode: VmOpcode,
15    pub a: F,
16    pub b: F,
17    pub c: F,
18    pub d: F,
19    pub e: F,
20    pub f: F,
21    pub g: F,
22}
23
24impl<F: Field> Instruction<F> {
25    #[allow(clippy::too_many_arguments)]
26    pub fn from_isize(opcode: VmOpcode, a: isize, b: isize, c: isize, d: isize, e: isize) -> Self {
27        Self {
28            opcode,
29            a: isize_to_field::<F>(a),
30            b: isize_to_field::<F>(b),
31            c: isize_to_field::<F>(c),
32            d: isize_to_field::<F>(d),
33            e: isize_to_field::<F>(e),
34            f: isize_to_field::<F>(0),
35            g: isize_to_field::<F>(0),
36        }
37    }
38
39    pub fn from_usize<const N: usize>(opcode: VmOpcode, operands: [usize; N]) -> Self {
40        let mut operands = operands.map(F::from_canonical_usize).to_vec();
41        operands.resize(NUM_OPERANDS, F::ZERO);
42        Self {
43            opcode,
44            a: operands[0],
45            b: operands[1],
46            c: operands[2],
47            d: operands[3],
48            e: operands[4],
49            f: operands[5],
50            g: operands[6],
51        }
52    }
53
54    #[allow(clippy::too_many_arguments)]
55    pub fn large_from_isize(
56        opcode: VmOpcode,
57        a: isize,
58        b: isize,
59        c: isize,
60        d: isize,
61        e: isize,
62        f: isize,
63        g: isize,
64    ) -> Self {
65        Self {
66            opcode,
67            a: isize_to_field::<F>(a),
68            b: isize_to_field::<F>(b),
69            c: isize_to_field::<F>(c),
70            d: isize_to_field::<F>(d),
71            e: isize_to_field::<F>(e),
72            f: isize_to_field::<F>(f),
73            g: isize_to_field::<F>(g),
74        }
75    }
76
77    pub fn phantom(discriminant: PhantomDiscriminant, a: F, b: F, c_upper: u16) -> Self {
78        Self {
79            opcode: SystemOpcode::PHANTOM.global_opcode(),
80            a,
81            b,
82            c: F::from_canonical_u32((discriminant.0 as u32) | ((c_upper as u32) << 16)),
83            ..Default::default()
84        }
85    }
86
87    pub fn debug(discriminant: PhantomDiscriminant) -> Self {
88        Self {
89            opcode: SystemOpcode::PHANTOM.global_opcode(),
90            c: F::from_canonical_u32(discriminant.0 as u32),
91            ..Default::default()
92        }
93    }
94
95    pub fn operands(&self) -> Vec<F> {
96        vec![self.a, self.b, self.c, self.d, self.e, self.f, self.g]
97    }
98}
99
100impl<T: Default> Default for Instruction<T> {
101    fn default() -> Self {
102        Self {
103            opcode: VmOpcode::from_usize(0), // there is no real default opcode, this field must always be set
104            a: T::default(),
105            b: T::default(),
106            c: T::default(),
107            d: T::default(),
108            e: T::default(),
109            f: T::default(),
110            g: T::default(),
111        }
112    }
113}
114
115#[derive(Debug, Clone, Default, Serialize, Deserialize)]
116pub struct DebugInfo {
117    pub dsl_instruction: String,
118    pub trace: Option<Backtrace>,
119}
120
121impl DebugInfo {
122    pub fn new(dsl_instruction: String, trace: Option<Backtrace>) -> Self {
123        Self {
124            dsl_instruction,
125            trace,
126        }
127    }
128}