1#[cfg(not(feature = "std"))]
2use alloc::{vec, vec::Vec};
3use core::fmt::Display;
4
5use crate::hints::{Hint, PythonicHint};
6use crate::operand::{CellRef, DerefOrImmediate, ResOperand};
7
8#[cfg(test)]
9#[path = "instructions_test.rs"]
10mod test;
11
12#[derive(Debug, Eq, PartialEq, Clone)]
14pub enum InstructionBody {
15 AddAp(AddApInstruction),
16 AssertEq(AssertEqInstruction),
17 QM31AssertEq(AssertEqInstruction),
18 Call(CallInstruction),
19 Jnz(JnzInstruction),
20 Jump(JumpInstruction),
21 Ret(RetInstruction),
22 Blake2sCompress(Blake2sCompressInstruction),
23}
24impl InstructionBody {
25 pub fn op_size(&self) -> usize {
26 match self {
28 InstructionBody::AddAp(insn) => insn.op_size(),
29 InstructionBody::AssertEq(insn) | InstructionBody::QM31AssertEq(insn) => insn.op_size(),
30 InstructionBody::Call(insn) => insn.op_size(),
31 InstructionBody::Jump(insn) => insn.op_size(),
32 InstructionBody::Jnz(insn) => insn.op_size(),
33 InstructionBody::Ret(insn) => insn.op_size(),
34 InstructionBody::Blake2sCompress(insn) => insn.op_size(),
35 }
36 }
37}
38impl Display for InstructionBody {
39 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40 match self {
41 InstructionBody::AddAp(insn) => write!(f, "{insn}",),
42 InstructionBody::AssertEq(insn) => write!(f, "{insn}",),
43 InstructionBody::QM31AssertEq(insn) => write!(f, "{{QM31}} {insn}",),
44 InstructionBody::Call(insn) => write!(f, "{insn}",),
45 InstructionBody::Jnz(insn) => write!(f, "{insn}",),
46 InstructionBody::Jump(insn) => write!(f, "{insn}",),
47 InstructionBody::Ret(insn) => write!(f, "{insn}",),
48 InstructionBody::Blake2sCompress(insn) => write!(f, "{insn}",),
49 }
50 }
51}
52
53#[derive(Debug, Eq, PartialEq, Clone)]
55pub struct Instruction {
56 pub body: InstructionBody,
57 pub inc_ap: bool,
58 pub hints: Vec<Hint>,
59}
60impl Instruction {
61 pub fn new(body: InstructionBody, inc_ap: bool) -> Self {
62 Self { body, inc_ap, hints: vec![] }
63 }
64}
65
66impl Display for Instruction {
67 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68 for hint in &self.hints {
69 let hint_str = hint.get_pythonic_hint();
70 if hint_str.starts_with('\n') {
72 writeln!(f, "%{{{hint_str}%}}")
73 } else {
74 writeln!(f, "%{{ {hint_str} %}}")
75 }?
76 }
77
78 write!(f, "{}", self.body)?;
79 if self.inc_ap {
80 write!(f, ", ap++")?
81 };
82 Ok(())
83 }
84}
85
86#[derive(Debug, Eq, PartialEq, Clone)]
88pub struct CallInstruction {
89 pub target: DerefOrImmediate,
90 pub relative: bool,
91}
92impl Display for CallInstruction {
93 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
94 write!(f, "call {} {}", if self.relative { "rel" } else { "abs" }, self.target,)
95 }
96}
97impl CallInstruction {
98 pub fn op_size(&self) -> usize {
99 match &self.target {
100 DerefOrImmediate::Deref(_) => 1,
101 DerefOrImmediate::Immediate(_) => 2,
102 }
103 }
104}
105
106#[derive(Debug, Eq, PartialEq, Clone)]
108pub struct JumpInstruction {
109 pub target: DerefOrImmediate,
110 pub relative: bool,
111}
112impl JumpInstruction {
113 pub fn op_size(&self) -> usize {
114 match &self.target {
115 DerefOrImmediate::Deref(_) => 1,
116 DerefOrImmediate::Immediate(_) => 2,
117 }
118 }
119}
120impl Display for JumpInstruction {
121 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122 write!(f, "jmp {} {}", if self.relative { "rel" } else { "abs" }, self.target,)
123 }
124}
125
126#[derive(Debug, Eq, PartialEq, Clone)]
128pub struct JnzInstruction {
129 pub jump_offset: DerefOrImmediate,
130 pub condition: CellRef,
131}
132impl JnzInstruction {
133 pub fn op_size(&self) -> usize {
134 match &self.jump_offset {
135 DerefOrImmediate::Deref(_) => 1,
136 DerefOrImmediate::Immediate(_) => 2,
137 }
138 }
139}
140impl Display for JnzInstruction {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 write!(f, "jmp rel {} if {} != 0", self.jump_offset, self.condition)
143 }
144}
145
146pub fn op_size_based_on_res_operands(operand: &ResOperand) -> usize {
148 match operand {
149 ResOperand::Deref(_) => 1,
150 ResOperand::DoubleDeref(_, _) => 1,
151 ResOperand::Immediate(_) => 2,
152 ResOperand::BinOp(op) => match op.b {
153 DerefOrImmediate::Immediate(_) => 2,
154 DerefOrImmediate::Deref(_) => 1,
155 },
156 }
157}
158
159#[derive(Debug, Eq, PartialEq, Clone)]
161pub struct AssertEqInstruction {
162 pub a: CellRef,
163 pub b: ResOperand,
164}
165impl AssertEqInstruction {
166 pub fn op_size(&self) -> usize {
167 op_size_based_on_res_operands(&self.b)
168 }
169}
170impl Display for AssertEqInstruction {
171 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172 write!(f, "{} = {}", self.a, self.b)
173 }
174}
175
176#[derive(Debug, Eq, PartialEq, Clone)]
178pub struct RetInstruction {}
179impl Display for RetInstruction {
180 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181 write!(f, "ret")
182 }
183}
184
185impl RetInstruction {
186 pub fn op_size(&self) -> usize {
187 1
188 }
189}
190
191#[derive(Debug, Eq, PartialEq, Clone)]
193pub struct AddApInstruction {
194 pub operand: ResOperand,
195}
196impl AddApInstruction {
197 pub fn op_size(&self) -> usize {
198 op_size_based_on_res_operands(&self.operand)
199 }
200}
201impl Display for AddApInstruction {
202 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 write!(f, "ap += {}", self.operand)
204 }
205}
206
207#[derive(Debug, Eq, PartialEq, Clone)]
209pub struct Blake2sCompressInstruction {
210 pub state: CellRef,
211 pub byte_count: CellRef,
212 pub message: CellRef,
213 pub finalize: bool,
214}
215impl Blake2sCompressInstruction {
216 pub fn op_size(&self) -> usize {
217 1
218 }
219}
220impl Display for Blake2sCompressInstruction {
221 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222 write!(
223 f,
224 "blake2s[state={}, message={}, byte_count={}, finalize={}] => [ap + 0]",
225 self.state, self.message, self.byte_count, self.finalize
226 )
227 }
228}