1use vm_core::{Felt, ZERO};
2
3use super::FastProcessor;
4use crate::{ErrorContext, ExecutionError, utils::split_element};
5
6impl FastProcessor {
7 pub fn op_u32split(&mut self) -> Result<(), ExecutionError> {
9 let top = self.stack_get(0);
10 let (hi, lo) = split_element(top);
11
12 self.increment_stack_size();
13 self.stack_write(0, hi);
14 self.stack_write(1, lo);
15
16 Ok(())
17 }
18
19 pub fn op_u32add(&mut self) -> Result<(), ExecutionError> {
21 self.u32_pop2_applyfn_push_lowhigh(|a, b| a + b)
22 }
23
24 pub fn op_u32add3(&mut self) -> Result<(), ExecutionError> {
31 let (sum_hi, sum_lo) = {
32 let c = self.stack_get(0).as_int();
33 let b = self.stack_get(1).as_int();
34 let a = self.stack_get(2).as_int();
35
36 if a > u32::MAX as u64 {
38 return Err(ExecutionError::not_u32_value(
39 Felt::new(a),
40 ZERO,
41 &ErrorContext::default(),
42 ));
43 }
44 if b > u32::MAX as u64 {
45 return Err(ExecutionError::not_u32_value(
46 Felt::new(b),
47 ZERO,
48 &ErrorContext::default(),
49 ));
50 }
51 if c > u32::MAX as u64 {
52 return Err(ExecutionError::not_u32_value(
53 Felt::new(c),
54 ZERO,
55 &ErrorContext::default(),
56 ));
57 }
58 let result = Felt::new(a + b + c);
59 split_element(result)
60 };
61
62 self.decrement_stack_size();
64 self.stack_write(0, sum_hi);
65 self.stack_write(1, sum_lo);
66 Ok(())
67 }
68
69 pub fn op_u32sub(&mut self, op_idx: usize) -> Result<(), ExecutionError> {
71 let op_idx = Felt::from(op_idx as u32);
72 self.u32_pop2_applyfn_push_results(op_idx, |first_old, second_old| {
73 let result = second_old.wrapping_sub(first_old);
74 let first_new = result >> 63;
75 let second_new = result & u32::MAX as u64;
76
77 Ok((first_new, second_new))
78 })
79 }
80
81 pub fn op_u32mul(&mut self) -> Result<(), ExecutionError> {
83 self.u32_pop2_applyfn_push_lowhigh(|a, b| a * b)
84 }
85
86 pub fn op_u32madd(&mut self) -> Result<(), ExecutionError> {
92 let (result_hi, result_lo) = {
93 let b = self.stack_get(0).as_int();
94 let a = self.stack_get(1).as_int();
95 let c = self.stack_get(2).as_int();
96
97 if b > u32::MAX as u64 {
99 return Err(ExecutionError::not_u32_value(
100 Felt::new(a),
101 ZERO,
102 &ErrorContext::default(),
103 ));
104 }
105 if a > u32::MAX as u64 {
106 return Err(ExecutionError::not_u32_value(
107 Felt::new(b),
108 ZERO,
109 &ErrorContext::default(),
110 ));
111 }
112 if c > u32::MAX as u64 {
113 return Err(ExecutionError::not_u32_value(
114 Felt::new(c),
115 ZERO,
116 &ErrorContext::default(),
117 ));
118 }
119 let result = Felt::new(a * b + c);
120 split_element(result)
121 };
122
123 self.decrement_stack_size();
125 self.stack_write(0, result_hi);
126 self.stack_write(1, result_lo);
127 Ok(())
128 }
129
130 pub fn op_u32div(&mut self, op_idx: usize) -> Result<(), ExecutionError> {
132 let clk = self.clk + op_idx;
133 self.u32_pop2_applyfn_push_results(ZERO, |first, second| {
134 if first == 0 {
135 return Err(ExecutionError::divide_by_zero(clk, &ErrorContext::default()));
136 }
137
138 let q = second / first;
140 let r = second - q * first;
141
142 Ok((r, q))
144 })
145 }
146
147 pub fn op_u32and(&mut self) -> Result<(), ExecutionError> {
149 self.u32_pop2_applyfn_push(|a, b| a & b)
150 }
151
152 pub fn op_u32xor(&mut self) -> Result<(), ExecutionError> {
154 self.u32_pop2_applyfn_push(|a, b| a ^ b)
155 }
156
157 pub fn op_u32assert2(&mut self, err_code: Felt) -> Result<(), ExecutionError> {
159 self.u32_pop2_applyfn_push_results(err_code, |first, second| Ok((first, second)))
160 }
161
162 fn u32_pop2_applyfn_push(
167 &mut self,
168 f: impl FnOnce(u64, u64) -> u64,
169 ) -> Result<(), ExecutionError> {
170 let b = self.stack_get(0).as_int();
171 let a = self.stack_get(1).as_int();
172
173 if b > u32::MAX as u64 {
175 return Err(ExecutionError::not_u32_value(
176 Felt::new(b),
177 ZERO,
178 &ErrorContext::default(),
179 ));
180 }
181 if a > u32::MAX as u64 {
182 return Err(ExecutionError::not_u32_value(
183 Felt::new(a),
184 ZERO,
185 &ErrorContext::default(),
186 ));
187 }
188
189 let result = f(a, b);
190 self.decrement_stack_size();
191 self.stack_write(0, Felt::new(result));
192
193 Ok(())
194 }
195
196 #[inline(always)]
207 fn u32_pop2_applyfn_push_lowhigh(
208 &mut self,
209 f: impl FnOnce(u64, u64) -> u64,
210 ) -> Result<(), ExecutionError> {
211 let b = self.stack_get(0).as_int();
212 let a = self.stack_get(1).as_int();
213
214 if a > u32::MAX as u64 {
216 return Err(ExecutionError::not_u32_value(
217 Felt::new(a),
218 ZERO,
219 &ErrorContext::default(),
220 ));
221 }
222 if b > u32::MAX as u64 {
223 return Err(ExecutionError::not_u32_value(
224 Felt::new(b),
225 ZERO,
226 &ErrorContext::default(),
227 ));
228 }
229
230 let result = Felt::new(f(a, b));
231 let (hi, lo) = split_element(result);
232
233 self.stack_write(0, hi);
234 self.stack_write(1, lo);
235 Ok(())
236 }
237
238 #[inline(always)]
243 fn u32_pop2_applyfn_push_results(
244 &mut self,
245 err_code: Felt,
246 f: impl FnOnce(u64, u64) -> Result<(u64, u64), ExecutionError>,
247 ) -> Result<(), ExecutionError> {
248 let first_old = self.stack_get(0).as_int();
249 let second_old = self.stack_get(1).as_int();
250
251 if first_old > u32::MAX as u64 {
253 return Err(ExecutionError::not_u32_value(
254 Felt::new(first_old),
255 err_code,
256 &ErrorContext::default(),
257 ));
258 }
259 if second_old > u32::MAX as u64 {
260 return Err(ExecutionError::not_u32_value(
261 Felt::new(second_old),
262 err_code,
263 &ErrorContext::default(),
264 ));
265 }
266
267 let (first_new, second_new) = f(first_old, second_old)?;
268
269 self.stack_write(0, Felt::new(first_new));
270 self.stack_write(1, Felt::new(second_new));
271 Ok(())
272 }
273}