openvm_instructions/
instruction.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use backtrace::Backtrace;
use openvm_stark_backend::p3_field::Field;
use serde::{Deserialize, Serialize};

use crate::{utils::isize_to_field, PhantomDiscriminant, SystemOpcode, UsizeOpcode, VmOpcode};

/// Number of operands of an instruction.
pub const NUM_OPERANDS: usize = 7;

#[allow(clippy::too_many_arguments)]
#[derive(Clone, Debug, PartialEq, Eq, derive_new::new, Serialize, Deserialize)]
pub struct Instruction<F> {
    pub opcode: VmOpcode,
    pub a: F,
    pub b: F,
    pub c: F,
    pub d: F,
    pub e: F,
    pub f: F,
    pub g: F,
}

impl<F: Field> Instruction<F> {
    #[allow(clippy::too_many_arguments)]
    pub fn from_isize(opcode: VmOpcode, a: isize, b: isize, c: isize, d: isize, e: isize) -> Self {
        Self {
            opcode,
            a: isize_to_field::<F>(a),
            b: isize_to_field::<F>(b),
            c: isize_to_field::<F>(c),
            d: isize_to_field::<F>(d),
            e: isize_to_field::<F>(e),
            f: isize_to_field::<F>(0),
            g: isize_to_field::<F>(0),
        }
    }

    pub fn from_usize<const N: usize>(opcode: VmOpcode, operands: [usize; N]) -> Self {
        let mut operands = operands.map(F::from_canonical_usize).to_vec();
        operands.resize(NUM_OPERANDS, F::ZERO);
        Self {
            opcode,
            a: operands[0],
            b: operands[1],
            c: operands[2],
            d: operands[3],
            e: operands[4],
            f: operands[5],
            g: operands[6],
        }
    }

    #[allow(clippy::too_many_arguments)]
    pub fn large_from_isize(
        opcode: VmOpcode,
        a: isize,
        b: isize,
        c: isize,
        d: isize,
        e: isize,
        f: isize,
        g: isize,
    ) -> Self {
        Self {
            opcode,
            a: isize_to_field::<F>(a),
            b: isize_to_field::<F>(b),
            c: isize_to_field::<F>(c),
            d: isize_to_field::<F>(d),
            e: isize_to_field::<F>(e),
            f: isize_to_field::<F>(f),
            g: isize_to_field::<F>(g),
        }
    }

    pub fn phantom(discriminant: PhantomDiscriminant, a: F, b: F, c_upper: u16) -> Self {
        Self {
            opcode: VmOpcode(SystemOpcode::PHANTOM.with_default_offset()),
            a,
            b,
            c: F::from_canonical_u32((discriminant.0 as u32) | ((c_upper as u32) << 16)),
            ..Default::default()
        }
    }

    pub fn debug(discriminant: PhantomDiscriminant) -> Self {
        Self {
            opcode: VmOpcode(SystemOpcode::PHANTOM.with_default_offset()),
            c: F::from_canonical_u32(discriminant.0 as u32),
            ..Default::default()
        }
    }
}

impl<T: Default> Default for Instruction<T> {
    fn default() -> Self {
        Self {
            opcode: VmOpcode::from_usize(0), // there is no real default opcode, this field must always be set
            a: T::default(),
            b: T::default(),
            c: T::default(),
            d: T::default(),
            e: T::default(),
            f: T::default(),
            g: T::default(),
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DebugInfo {
    pub dsl_instruction: String,
    pub trace: Option<Backtrace>,
}

impl DebugInfo {
    pub fn new(dsl_instruction: String, trace: Option<Backtrace>) -> Self {
        Self {
            dsl_instruction,
            trace,
        }
    }
}