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(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
119 let clk = self.clk;
120 self.u32_pop2_applyfn_push_results(
121 ZERO,
122 |first, second| {
123 if first == 0 {
124 return Err(ExecutionError::divide_by_zero(clk, err_ctx));
125 }
126
127 let q = second / first;
129 let r = second - q * first;
130
131 Ok((r, q))
133 },
134 err_ctx,
135 )
136 }
137
138 #[inline(always)]
140 pub fn op_u32and(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
141 self.u32_pop2_applyfn_push(|a, b| a & b, err_ctx)
142 }
143
144 #[inline(always)]
146 pub fn op_u32xor(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
147 self.u32_pop2_applyfn_push(|a, b| a ^ b, err_ctx)
148 }
149
150 #[inline(always)]
152 pub fn op_u32assert2(
153 &mut self,
154 err_code: Felt,
155 err_ctx: &impl ErrorContext,
156 ) -> Result<(), ExecutionError> {
157 self.u32_pop2_applyfn_push_results(err_code, |first, second| Ok((first, second)), err_ctx)
158 }
159
160 #[inline(always)]
165 fn u32_pop2_applyfn_push(
166 &mut self,
167 f: impl FnOnce(u64, u64) -> u64,
168 err_ctx: &impl ErrorContext,
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(Felt::new(b), ZERO, err_ctx));
176 }
177 if a > u32::MAX as u64 {
178 return Err(ExecutionError::not_u32_value(Felt::new(a), ZERO, err_ctx));
179 }
180
181 let result = f(a, b);
182 self.decrement_stack_size();
183 self.stack_write(0, Felt::new(result));
184
185 Ok(())
186 }
187
188 #[inline(always)]
199 fn u32_pop2_applyfn_push_lowhigh(
200 &mut self,
201 f: impl FnOnce(u64, u64) -> u64,
202 err_ctx: &impl ErrorContext,
203 ) -> Result<(), ExecutionError> {
204 let b = self.stack_get(0).as_int();
205 let a = self.stack_get(1).as_int();
206
207 if a > u32::MAX as u64 {
209 return Err(ExecutionError::not_u32_value(Felt::new(a), ZERO, err_ctx));
210 }
211 if b > u32::MAX as u64 {
212 return Err(ExecutionError::not_u32_value(Felt::new(b), ZERO, err_ctx));
213 }
214
215 let result = Felt::new(f(a, b));
216 let (hi, lo) = split_element(result);
217
218 self.stack_write(0, hi);
219 self.stack_write(1, lo);
220 Ok(())
221 }
222
223 #[inline(always)]
228 fn u32_pop2_applyfn_push_results(
229 &mut self,
230 err_code: Felt,
231 f: impl FnOnce(u64, u64) -> Result<(u64, u64), ExecutionError>,
232 err_ctx: &impl ErrorContext,
233 ) -> Result<(), ExecutionError> {
234 let first_old = self.stack_get(0).as_int();
235 let second_old = self.stack_get(1).as_int();
236
237 if first_old > u32::MAX as u64 {
239 return Err(ExecutionError::not_u32_value(Felt::new(first_old), err_code, err_ctx));
240 }
241 if second_old > u32::MAX as u64 {
242 return Err(ExecutionError::not_u32_value(Felt::new(second_old), err_code, err_ctx));
243 }
244
245 let (first_new, second_new) = f(first_old, second_old)?;
246
247 self.stack_write(0, Felt::new(first_new));
248 self.stack_write(1, Felt::new(second_new));
249 Ok(())
250 }
251}