1use miden_core::{Felt, ZERO};
2
3use super::FastProcessor;
4use crate::{ErrorContext, ExecutionError, utils::split_element};
5
6impl FastProcessor {
7 #[inline(always)]
9 pub fn op_u32split(&mut self) {
10 let top = self.stack_get(0);
11 let (hi, lo) = split_element(top);
12
13 self.increment_stack_size();
14 self.stack_write(0, hi);
15 self.stack_write(1, lo);
16 }
17
18 pub fn op_u32add(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
20 self.u32_pop2_applyfn_push_lowhigh(|a, b| a + b, err_ctx)
21 }
22
23 #[inline(always)]
30 pub fn op_u32add3(&mut self, err_ctx: &impl ErrorContext) -> 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(Felt::new(a), ZERO, err_ctx));
39 }
40 if b > u32::MAX as u64 {
41 return Err(ExecutionError::not_u32_value(Felt::new(b), ZERO, err_ctx));
42 }
43 if c > u32::MAX as u64 {
44 return Err(ExecutionError::not_u32_value(Felt::new(c), ZERO, err_ctx));
45 }
46 let result = Felt::new(a + b + c);
47 split_element(result)
48 };
49
50 self.decrement_stack_size();
52 self.stack_write(0, sum_hi);
53 self.stack_write(1, sum_lo);
54 Ok(())
55 }
56
57 #[inline(always)]
59 pub fn op_u32sub(
60 &mut self,
61 op_idx: usize,
62 err_ctx: &impl ErrorContext,
63 ) -> Result<(), ExecutionError> {
64 let op_idx = Felt::from(op_idx as u32);
65 self.u32_pop2_applyfn_push_results(
66 op_idx,
67 |first_old, second_old| {
68 let result = second_old.wrapping_sub(first_old);
69 let first_new = result >> 63;
70 let second_new = result & u32::MAX as u64;
71
72 Ok((first_new, second_new))
73 },
74 err_ctx,
75 )
76 }
77
78 pub fn op_u32mul(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
80 self.u32_pop2_applyfn_push_lowhigh(|a, b| a * b, err_ctx)
81 }
82
83 #[inline(always)]
89 pub fn op_u32madd(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
90 let (result_hi, result_lo) = {
91 let b = self.stack_get(0).as_int();
92 let a = self.stack_get(1).as_int();
93 let c = self.stack_get(2).as_int();
94
95 if b > u32::MAX as u64 {
97 return Err(ExecutionError::not_u32_value(Felt::new(a), ZERO, err_ctx));
98 }
99 if a > u32::MAX as u64 {
100 return Err(ExecutionError::not_u32_value(Felt::new(b), ZERO, err_ctx));
101 }
102 if c > u32::MAX as u64 {
103 return Err(ExecutionError::not_u32_value(Felt::new(c), ZERO, err_ctx));
104 }
105 let result = Felt::new(a * b + c);
106 split_element(result)
107 };
108
109 self.decrement_stack_size();
111 self.stack_write(0, result_hi);
112 self.stack_write(1, result_lo);
113 Ok(())
114 }
115
116 #[inline(always)]
118 pub fn op_u32div(
119 &mut self,
120 op_idx: usize,
121 err_ctx: &impl ErrorContext,
122 ) -> Result<(), ExecutionError> {
123 let clk = self.clk + op_idx;
124 self.u32_pop2_applyfn_push_results(
125 ZERO,
126 |first, second| {
127 if first == 0 {
128 return Err(ExecutionError::divide_by_zero(clk, err_ctx));
129 }
130
131 let q = second / first;
133 let r = second - q * first;
134
135 Ok((r, q))
137 },
138 err_ctx,
139 )
140 }
141
142 #[inline(always)]
144 pub fn op_u32and(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
145 self.u32_pop2_applyfn_push(|a, b| a & b, err_ctx)
146 }
147
148 #[inline(always)]
150 pub fn op_u32xor(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
151 self.u32_pop2_applyfn_push(|a, b| a ^ b, err_ctx)
152 }
153
154 #[inline(always)]
156 pub fn op_u32assert2(
157 &mut self,
158 err_code: Felt,
159 err_ctx: &impl ErrorContext,
160 ) -> Result<(), ExecutionError> {
161 self.u32_pop2_applyfn_push_results(err_code, |first, second| Ok((first, second)), err_ctx)
162 }
163
164 #[inline(always)]
169 fn u32_pop2_applyfn_push(
170 &mut self,
171 f: impl FnOnce(u64, u64) -> u64,
172 err_ctx: &impl ErrorContext,
173 ) -> Result<(), ExecutionError> {
174 let b = self.stack_get(0).as_int();
175 let a = self.stack_get(1).as_int();
176
177 if b > u32::MAX as u64 {
179 return Err(ExecutionError::not_u32_value(Felt::new(b), ZERO, err_ctx));
180 }
181 if a > u32::MAX as u64 {
182 return Err(ExecutionError::not_u32_value(Felt::new(a), ZERO, err_ctx));
183 }
184
185 let result = f(a, b);
186 self.decrement_stack_size();
187 self.stack_write(0, Felt::new(result));
188
189 Ok(())
190 }
191
192 #[inline(always)]
203 fn u32_pop2_applyfn_push_lowhigh(
204 &mut self,
205 f: impl FnOnce(u64, u64) -> u64,
206 err_ctx: &impl ErrorContext,
207 ) -> Result<(), ExecutionError> {
208 let b = self.stack_get(0).as_int();
209 let a = self.stack_get(1).as_int();
210
211 if a > u32::MAX as u64 {
213 return Err(ExecutionError::not_u32_value(Felt::new(a), ZERO, err_ctx));
214 }
215 if b > u32::MAX as u64 {
216 return Err(ExecutionError::not_u32_value(Felt::new(b), ZERO, err_ctx));
217 }
218
219 let result = Felt::new(f(a, b));
220 let (hi, lo) = split_element(result);
221
222 self.stack_write(0, hi);
223 self.stack_write(1, lo);
224 Ok(())
225 }
226
227 #[inline(always)]
232 fn u32_pop2_applyfn_push_results(
233 &mut self,
234 err_code: Felt,
235 f: impl FnOnce(u64, u64) -> Result<(u64, u64), ExecutionError>,
236 err_ctx: &impl ErrorContext,
237 ) -> Result<(), ExecutionError> {
238 let first_old = self.stack_get(0).as_int();
239 let second_old = self.stack_get(1).as_int();
240
241 if first_old > u32::MAX as u64 {
243 return Err(ExecutionError::not_u32_value(Felt::new(first_old), err_code, err_ctx));
244 }
245 if second_old > u32::MAX as u64 {
246 return Err(ExecutionError::not_u32_value(Felt::new(second_old), err_code, err_ctx));
247 }
248
249 let (first_new, second_new) = f(first_old, second_old)?;
250
251 self.stack_write(0, Felt::new(first_new));
252 self.stack_write(1, Felt::new(second_new));
253 Ok(())
254 }
255}