sp1_recursion_compiler/ir/
builder.rs

1use std::{cell::UnsafeCell, ptr};
2
3use p3_field::AbstractField;
4use sp1_primitives::types::RecursionProgramType;
5
6use super::{
7    Array, Config, DslIr, DslIrBlock, Ext, ExtHandle, ExtOperations, Felt, FeltHandle,
8    FeltOperations, FromConstant, SymbolicExt, SymbolicFelt, SymbolicUsize, SymbolicVar, Usize,
9    Var, VarHandle, VarOperations, Variable,
10};
11
12#[derive(Debug, Clone)]
13pub struct InnerBuilder<C: Config> {
14    pub(crate) variable_count: u32,
15    pub operations: Vec<DslIr<C>>,
16}
17
18/// A builder for the DSL.
19///
20/// Can compile to both assembly and a set of constraints.
21#[derive(Debug)]
22pub struct Builder<C: Config> {
23    pub(crate) inner: Box<UnsafeCell<InnerBuilder<C>>>,
24    pub(crate) nb_public_values: Option<Var<C::N>>,
25    pub(crate) witness_var_count: u32,
26    pub(crate) witness_felt_count: u32,
27    pub(crate) witness_ext_count: u32,
28    pub(crate) var_handle: Box<VarHandle<C::N>>,
29    pub(crate) felt_handle: Box<FeltHandle<C::F>>,
30    pub(crate) ext_handle: Box<ExtHandle<C::F, C::EF>>,
31    pub(crate) p2_hash_num: Var<C::N>,
32    pub(crate) debug: bool,
33    pub(crate) is_sub_builder: bool,
34    pub program_type: RecursionProgramType,
35}
36
37impl<C: Config> Default for Builder<C> {
38    fn default() -> Self {
39        Self::new(RecursionProgramType::Core)
40    }
41}
42
43impl<C: Config> Builder<C> {
44    pub fn new(program_type: RecursionProgramType) -> Self {
45        // We need to create a temporary placeholder for the p2_hash_num variable.
46        let placeholder_p2_hash_num = Var::new(0, ptr::null_mut());
47
48        let mut inner = Box::new(UnsafeCell::new(InnerBuilder {
49            variable_count: 0,
50            operations: Default::default(),
51        }));
52
53        let var_handle = Box::new(VarOperations::var_handle(&mut inner));
54        let mut ext_handle = Box::new(ExtOperations::ext_handle(&mut inner));
55        let felt_handle = Box::new(FeltOperations::felt_handle(
56            &mut inner,
57            ext_handle.as_mut() as *mut _ as *mut (),
58        ));
59
60        let mut new_builder = Self {
61            inner,
62            witness_var_count: 0,
63            witness_felt_count: 0,
64            witness_ext_count: 0,
65            nb_public_values: None,
66            var_handle,
67            felt_handle,
68            ext_handle,
69            p2_hash_num: placeholder_p2_hash_num,
70            debug: false,
71            is_sub_builder: false,
72            program_type,
73        };
74
75        new_builder.p2_hash_num = new_builder.uninit();
76        new_builder
77    }
78
79    /// Creates a new builder with a given number of counts for each type.
80    pub fn new_sub_builder(
81        variable_count: u32,
82        nb_public_values: Option<Var<C::N>>,
83        p2_hash_num: Var<C::N>,
84        debug: bool,
85        program_type: RecursionProgramType,
86    ) -> Self {
87        let mut builder = Self::new(program_type);
88        builder.inner.get_mut().variable_count = variable_count;
89        builder.nb_public_values = nb_public_values;
90        builder.p2_hash_num = p2_hash_num;
91        builder.debug = debug;
92
93        builder
94    }
95
96    /// Convenience function for creating a new sub builder.
97    pub fn sub_builder(&self) -> Self {
98        Builder::<C>::new_sub_builder(
99            self.variable_count(),
100            self.nb_public_values,
101            self.p2_hash_num,
102            self.debug,
103            self.program_type,
104        )
105    }
106
107    /// Pushes an operation to the builder.
108    #[inline(always)]
109    pub fn push_op(&mut self, op: DslIr<C>) {
110        self.inner.get_mut().operations.push(op);
111    }
112
113    pub fn extend_ops(&mut self, ops: impl IntoIterator<Item = DslIr<C>>) {
114        self.inner.get_mut().operations.extend(ops);
115    }
116
117    #[inline(always)]
118    // Record a trace if the "debug" feature is enabled.
119    pub fn push_backtrace(&mut self) {
120        #[cfg(feature = "debug")]
121        self.push_op(DslIr::DebugBacktrace(backtrace::Backtrace::new_unresolved()));
122    }
123
124    /// Pushes an operation to the builder and records a trace if the "debug" feature is enabled.
125    #[inline(always)]
126    pub fn push_traced_op(&mut self, op: DslIr<C>) {
127        self.push_backtrace();
128        self.push_op(op);
129    }
130
131    pub fn variable_count(&self) -> u32 {
132        unsafe { (*self.inner.get()).variable_count }
133    }
134
135    pub fn set_variable_count(&mut self, variable_count: u32) {
136        self.inner.get_mut().variable_count = variable_count;
137    }
138
139    pub fn into_operations(self) -> Vec<DslIr<C>> {
140        self.inner.into_inner().operations
141    }
142
143    pub fn into_root_block(self) -> DslIrBlock<C> {
144        let addrs_written = 0..self.variable_count();
145        DslIrBlock { ops: self.inner.into_inner().operations, addrs_written }
146    }
147
148    /// Get a mutable reference to the list of operations.
149    /// Can be used for adjusting evaluation order using the utility functions from [`std::mem`].
150    ///
151    /// One use case is to move "lazy" evaluation out of a parallel context.
152    pub fn get_mut_operations(&mut self) -> &mut Vec<DslIr<C>> {
153        &mut self.inner.get_mut().operations
154    }
155
156    /// Creates an uninitialized variable.
157    pub fn uninit<V: Variable<C>>(&mut self) -> V {
158        V::uninit(self)
159    }
160
161    /// Evaluates an expression and returns a variable.
162    pub fn eval<V: Variable<C>, E: Into<V::Expression>>(&mut self, expr: E) -> V {
163        let dst = V::uninit(self);
164        dst.assign(expr.into(), self);
165        dst
166    }
167
168    /// Evaluates a constant expression and returns a variable.
169    pub fn constant<V: FromConstant<C>>(&mut self, value: V::Constant) -> V {
170        V::constant(value, self)
171    }
172
173    /// Assigns an expression to a variable.
174    pub fn assign<V: Variable<C>, E: Into<V::Expression>>(&mut self, dst: V, expr: E) {
175        dst.assign(expr.into(), self);
176    }
177
178    /// Asserts that two expressions are equal.
179    pub fn assert_eq<V: Variable<C>>(
180        &mut self,
181        lhs: impl Into<V::Expression>,
182        rhs: impl Into<V::Expression>,
183    ) {
184        V::assert_eq(lhs, rhs, self);
185    }
186
187    /// Asserts that two expressions are not equal.
188    pub fn assert_ne<V: Variable<C>>(
189        &mut self,
190        lhs: impl Into<V::Expression>,
191        rhs: impl Into<V::Expression>,
192    ) {
193        V::assert_ne(lhs, rhs, self);
194    }
195
196    /// Assert that two vars are equal.
197    pub fn assert_var_eq<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
198        &mut self,
199        lhs: LhsExpr,
200        rhs: RhsExpr,
201    ) {
202        self.assert_eq::<Var<C::N>>(lhs, rhs);
203    }
204
205    /// Assert that two vars are not equal.
206    pub fn assert_var_ne<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
207        &mut self,
208        lhs: LhsExpr,
209        rhs: RhsExpr,
210    ) {
211        self.assert_ne::<Var<C::N>>(lhs, rhs);
212    }
213
214    /// Assert that two felts are equal.
215    pub fn assert_felt_eq<LhsExpr: Into<SymbolicFelt<C::F>>, RhsExpr: Into<SymbolicFelt<C::F>>>(
216        &mut self,
217        lhs: LhsExpr,
218        rhs: RhsExpr,
219    ) {
220        self.assert_eq::<Felt<C::F>>(lhs, rhs);
221    }
222
223    /// Assert that two felts are not equal.
224    pub fn assert_felt_ne<LhsExpr: Into<SymbolicFelt<C::F>>, RhsExpr: Into<SymbolicFelt<C::F>>>(
225        &mut self,
226        lhs: LhsExpr,
227        rhs: RhsExpr,
228    ) {
229        self.assert_ne::<Felt<C::F>>(lhs, rhs);
230    }
231
232    /// Assert that two usizes are equal.
233    pub fn assert_usize_eq<
234        LhsExpr: Into<SymbolicUsize<C::N>>,
235        RhsExpr: Into<SymbolicUsize<C::N>>,
236    >(
237        &mut self,
238        lhs: LhsExpr,
239        rhs: RhsExpr,
240    ) {
241        self.assert_eq::<Usize<C::N>>(lhs, rhs);
242    }
243
244    /// Assert that two usizes are not equal.
245    pub fn assert_usize_ne(
246        &mut self,
247        lhs: impl Into<SymbolicUsize<C::N>>,
248        rhs: impl Into<SymbolicUsize<C::N>>,
249    ) {
250        self.assert_ne::<Usize<C::N>>(lhs, rhs);
251    }
252
253    /// Assert that two exts are equal.
254    pub fn assert_ext_eq<
255        LhsExpr: Into<SymbolicExt<C::F, C::EF>>,
256        RhsExpr: Into<SymbolicExt<C::F, C::EF>>,
257    >(
258        &mut self,
259        lhs: LhsExpr,
260        rhs: RhsExpr,
261    ) {
262        self.assert_eq::<Ext<C::F, C::EF>>(lhs, rhs);
263    }
264
265    /// Assert that two exts are not equal.
266    pub fn assert_ext_ne<
267        LhsExpr: Into<SymbolicExt<C::F, C::EF>>,
268        RhsExpr: Into<SymbolicExt<C::F, C::EF>>,
269    >(
270        &mut self,
271        lhs: LhsExpr,
272        rhs: RhsExpr,
273    ) {
274        self.assert_ne::<Ext<C::F, C::EF>>(lhs, rhs);
275    }
276
277    pub fn lt(&mut self, lhs: Var<C::N>, rhs: Var<C::N>) -> Var<C::N> {
278        let result = self.uninit();
279        self.push_op(DslIr::LessThan(result, lhs, rhs));
280        result
281    }
282
283    /// Evaluate a block of operations if two expressions are equal.
284    pub fn if_eq<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
285        &mut self,
286        lhs: LhsExpr,
287        rhs: RhsExpr,
288    ) -> IfBuilder<C> {
289        IfBuilder { lhs: lhs.into(), rhs: rhs.into(), is_eq: true, builder: self }
290    }
291
292    /// Evaluate a block of operations if two expressions are not equal.
293    pub fn if_ne<LhsExpr: Into<SymbolicVar<C::N>>, RhsExpr: Into<SymbolicVar<C::N>>>(
294        &mut self,
295        lhs: LhsExpr,
296        rhs: RhsExpr,
297    ) -> IfBuilder<C> {
298        IfBuilder { lhs: lhs.into(), rhs: rhs.into(), is_eq: false, builder: self }
299    }
300
301    /// Evaluate a block of operations over a range from start to end.
302    pub fn range(
303        &mut self,
304        start: impl Into<Usize<C::N>>,
305        end: impl Into<Usize<C::N>>,
306    ) -> RangeBuilder<C> {
307        RangeBuilder { start: start.into(), end: end.into(), builder: self, step_size: 1 }
308    }
309
310    /// Break out of a loop.
311    pub fn break_loop(&mut self) {
312        self.push_op(DslIr::Break);
313    }
314
315    pub fn print_debug(&mut self, val: usize) {
316        let constant = self.eval(C::N::from_canonical_usize(val));
317        self.print_v(constant);
318    }
319
320    /// Print a variable.
321    pub fn print_v(&mut self, dst: Var<C::N>) {
322        self.push_op(DslIr::PrintV(dst));
323    }
324
325    /// Print a felt.
326    pub fn print_f(&mut self, dst: Felt<C::F>) {
327        self.push_op(DslIr::PrintF(dst));
328    }
329
330    /// Print an ext.
331    pub fn print_e(&mut self, dst: Ext<C::F, C::EF>) {
332        self.push_op(DslIr::PrintE(dst));
333    }
334
335    /// Hint the length of the next vector of variables.
336    pub fn hint_len(&mut self) -> Var<C::N> {
337        let len = self.uninit();
338        self.push_op(DslIr::HintLen(len));
339        len
340    }
341
342    /// Hint a single variable.
343    pub fn hint_var(&mut self) -> Var<C::N> {
344        let len = self.hint_len();
345        let arr = self.dyn_array(len);
346        self.push_op(DslIr::HintVars(arr.clone()));
347        self.get(&arr, 0)
348    }
349
350    /// Hint a single felt.
351    pub fn hint_felt(&mut self) -> Felt<C::F> {
352        let len = self.hint_len();
353        let arr = self.dyn_array(len);
354        self.push_op(DslIr::HintFelts(arr.clone()));
355        self.get(&arr, 0)
356    }
357
358    /// Hint a single ext.
359    pub fn hint_ext(&mut self) -> Ext<C::F, C::EF> {
360        let len = self.hint_len();
361        let arr = self.dyn_array(len);
362        self.push_op(DslIr::HintExts(arr.clone()));
363        self.get(&arr, 0)
364    }
365
366    /// Hint a vector of variables.
367    pub fn hint_vars(&mut self) -> Array<C, Var<C::N>> {
368        let len = self.hint_len();
369        let arr = self.dyn_array(len);
370        self.push_op(DslIr::HintVars(arr.clone()));
371        arr
372    }
373
374    /// Hint a vector of felts.
375    pub fn hint_felts(&mut self) -> Array<C, Felt<C::F>> {
376        let len = self.hint_len();
377        let arr = self.dyn_array(len);
378        self.push_op(DslIr::HintFelts(arr.clone()));
379        arr
380    }
381
382    /// Hint a vector of exts.
383    pub fn hint_exts(&mut self) -> Array<C, Ext<C::F, C::EF>> {
384        let len = self.hint_len();
385        let arr = self.dyn_array(len);
386        self.push_op(DslIr::HintExts(arr.clone()));
387        arr
388    }
389
390    pub fn witness_var(&mut self) -> Var<C::N> {
391        assert!(!self.is_sub_builder, "Cannot create a witness var with a sub builder");
392        let witness = self.uninit();
393        self.push_op(DslIr::WitnessVar(witness, self.witness_var_count));
394        self.witness_var_count += 1;
395        witness
396    }
397
398    pub fn witness_felt(&mut self) -> Felt<C::F> {
399        assert!(!self.is_sub_builder, "Cannot create a witness felt with a sub builder");
400        let witness = self.uninit();
401        self.push_op(DslIr::WitnessFelt(witness, self.witness_felt_count));
402        self.witness_felt_count += 1;
403        witness
404    }
405
406    pub fn witness_ext(&mut self) -> Ext<C::F, C::EF> {
407        assert!(!self.is_sub_builder, "Cannot create a witness ext with a sub builder");
408        let witness = self.uninit();
409        self.push_op(DslIr::WitnessExt(witness, self.witness_ext_count));
410        self.witness_ext_count += 1;
411        witness
412    }
413
414    /// Throws an error.
415    pub fn error(&mut self) {
416        self.push_traced_op(DslIr::Error());
417    }
418
419    /// Materializes a usize into a variable.
420    pub fn materialize(&mut self, num: Usize<C::N>) -> Var<C::N> {
421        match num {
422            Usize::Const(num) => self.eval(C::N::from_canonical_usize(num)),
423            Usize::Var(num) => num,
424        }
425    }
426
427    /// Register a felt as public value.  This is append to the proof's public values buffer.
428    pub fn register_public_value(&mut self, val: Felt<C::F>) {
429        self.push_op(DslIr::RegisterPublicValue(val));
430    }
431
432    /// Register and commits a felt as public value.  This value will be constrained when verified.
433    pub fn commit_public_value(&mut self, val: Felt<C::F>) {
434        assert!(!self.is_sub_builder, "Cannot commit to a public value with a sub builder");
435        if self.nb_public_values.is_none() {
436            self.nb_public_values = Some(self.eval(C::N::zero()));
437        }
438        let nb_public_values = *self.nb_public_values.as_ref().unwrap();
439
440        self.push_op(DslIr::Commit(val, nb_public_values));
441        self.assign(nb_public_values, nb_public_values + C::N::one());
442    }
443
444    /// Commits an array of felts in public values.
445    pub fn commit_public_values(&mut self, vals: &Array<C, Felt<C::F>>) {
446        assert!(!self.is_sub_builder, "Cannot commit to public values with a sub builder");
447        let len = vals.len();
448        self.range(0, len).for_each(|i, builder| {
449            let val = builder.get(vals, i);
450            builder.commit_public_value(val);
451        });
452    }
453
454    pub fn commit_vkey_hash_circuit(&mut self, var: Var<C::N>) {
455        self.push_op(DslIr::CircuitCommitVkeyHash(var));
456    }
457
458    pub fn commit_committed_values_digest_circuit(&mut self, var: Var<C::N>) {
459        self.push_op(DslIr::CircuitCommitCommittedValuesDigest(var));
460    }
461
462    pub fn reduce_e(&mut self, ext: Ext<C::F, C::EF>) {
463        self.push_op(DslIr::ReduceE(ext));
464    }
465
466    pub fn felt2var_circuit(&mut self, felt: Felt<C::F>) -> Var<C::N> {
467        let var = self.uninit();
468        self.push_op(DslIr::CircuitFelt2Var(felt, var));
469        var
470    }
471
472    pub fn cycle_tracker(&mut self, name: &str) {
473        self.push_op(DslIr::CycleTracker(name.to_string()));
474    }
475
476    pub fn halt(&mut self) {
477        self.push_op(DslIr::Halt);
478    }
479}
480
481/// A builder for the DSL that handles if statements.
482#[allow(dead_code)]
483pub struct IfBuilder<'a, C: Config> {
484    lhs: SymbolicVar<C::N>,
485    rhs: SymbolicVar<C::N>,
486    is_eq: bool,
487    pub(crate) builder: &'a mut Builder<C>,
488}
489
490/// A set of conditions that if statements can be based on.
491#[allow(dead_code)]
492enum IfCondition<N> {
493    EqConst(N, N),
494    NeConst(N, N),
495    Eq(Var<N>, Var<N>),
496    EqI(Var<N>, N),
497    Ne(Var<N>, Var<N>),
498    NeI(Var<N>, N),
499}
500
501impl<C: Config> IfBuilder<'_, C> {
502    pub fn then(mut self, mut f: impl FnMut(&mut Builder<C>)) {
503        // Get the condition reduced from the expressions for lhs and rhs.
504        let condition = self.condition();
505
506        // Execute the `then` block and collect the instructions.
507        let mut f_builder = Builder::<C>::new_sub_builder(
508            self.builder.variable_count(),
509            self.builder.nb_public_values,
510            self.builder.p2_hash_num,
511            self.builder.debug,
512            self.builder.program_type,
513        );
514        f(&mut f_builder);
515        self.builder.p2_hash_num = f_builder.p2_hash_num;
516
517        let then_instructions = f_builder.into_operations();
518
519        // Dispatch instructions to the correct conditional block.
520        match condition {
521            IfCondition::EqConst(lhs, rhs) => {
522                if lhs == rhs {
523                    self.builder.extend_ops(then_instructions);
524                }
525            }
526            IfCondition::NeConst(lhs, rhs) => {
527                if lhs != rhs {
528                    self.builder.extend_ops(then_instructions);
529                }
530            }
531            IfCondition::Eq(lhs, rhs) => {
532                let op = DslIr::IfEq(Box::new((lhs, rhs, then_instructions, Default::default())));
533                self.builder.push_op(op);
534            }
535            IfCondition::EqI(lhs, rhs) => {
536                let op = DslIr::IfEqI(Box::new((lhs, rhs, then_instructions, Default::default())));
537                self.builder.push_op(op);
538            }
539            IfCondition::Ne(lhs, rhs) => {
540                let op = DslIr::IfNe(Box::new((lhs, rhs, then_instructions, Default::default())));
541                self.builder.push_op(op);
542            }
543            IfCondition::NeI(lhs, rhs) => {
544                let op = DslIr::IfNeI(Box::new((lhs, rhs, then_instructions, Default::default())));
545                self.builder.push_op(op);
546            }
547        }
548    }
549
550    pub fn then_or_else(
551        mut self,
552        mut then_f: impl FnMut(&mut Builder<C>),
553        mut else_f: impl FnMut(&mut Builder<C>),
554    ) {
555        // Get the condition reduced from the expressions for lhs and rhs.
556        let condition = self.condition();
557        let mut then_builder = Builder::<C>::new_sub_builder(
558            self.builder.variable_count(),
559            self.builder.nb_public_values,
560            self.builder.p2_hash_num,
561            self.builder.debug,
562            self.builder.program_type,
563        );
564
565        // Execute the `then` and `else_then` blocks and collect the instructions.
566        then_f(&mut then_builder);
567        self.builder.p2_hash_num = then_builder.p2_hash_num;
568
569        let then_instructions = then_builder.into_operations();
570
571        let mut else_builder = Builder::<C>::new_sub_builder(
572            self.builder.variable_count(),
573            self.builder.nb_public_values,
574            self.builder.p2_hash_num,
575            self.builder.debug,
576            self.builder.program_type,
577        );
578        else_f(&mut else_builder);
579        self.builder.p2_hash_num = else_builder.p2_hash_num;
580
581        let else_instructions = else_builder.into_operations();
582
583        // Dispatch instructions to the correct conditional block.
584        match condition {
585            IfCondition::EqConst(lhs, rhs) => {
586                if lhs == rhs {
587                    self.builder.extend_ops(then_instructions);
588                } else {
589                    self.builder.extend_ops(else_instructions);
590                }
591            }
592            IfCondition::NeConst(lhs, rhs) => {
593                if lhs != rhs {
594                    self.builder.extend_ops(then_instructions);
595                } else {
596                    self.builder.extend_ops(else_instructions);
597                }
598            }
599            IfCondition::Eq(lhs, rhs) => {
600                let op = DslIr::IfEq(Box::new((lhs, rhs, then_instructions, else_instructions)));
601                self.builder.push_op(op);
602            }
603            IfCondition::EqI(lhs, rhs) => {
604                let op = DslIr::IfEqI(Box::new((lhs, rhs, then_instructions, else_instructions)));
605                self.builder.push_op(op);
606            }
607            IfCondition::Ne(lhs, rhs) => {
608                let op = DslIr::IfNe(Box::new((lhs, rhs, then_instructions, else_instructions)));
609                self.builder.push_op(op);
610            }
611            IfCondition::NeI(lhs, rhs) => {
612                let op = DslIr::IfNeI(Box::new((lhs, rhs, then_instructions, else_instructions)));
613                self.builder.push_op(op);
614            }
615        }
616    }
617
618    fn condition(&mut self) -> IfCondition<C::N> {
619        unimplemented!("Deprecated")
620        // match (self.lhs.clone(), self.rhs.clone(), self.is_eq) {
621        //     (SymbolicVar::Const(lhs, _), SymbolicVar::Const(rhs, _), true) => {
622        //         IfCondition::EqConst(lhs, rhs)
623        //     }
624        //     (SymbolicVar::Const(lhs, _), SymbolicVar::Const(rhs, _), false) => {
625        //         IfCondition::NeConst(lhs, rhs)
626        //     }
627        //     (SymbolicVar::Const(lhs, _), SymbolicVar::Val(rhs, _), true) => {
628        //         IfCondition::EqI(rhs, lhs)
629        //     }
630        //     (SymbolicVar::Const(lhs, _), SymbolicVar::Val(rhs, _), false) => {
631        //         IfCondition::NeI(rhs, lhs)
632        //     }
633        //     (SymbolicVar::Const(lhs, _), rhs, true) => {
634        //         let rhs: Var<C::N> = self.builder.eval(rhs);
635        //         IfCondition::EqI(rhs, lhs)
636        //     }
637        //     (SymbolicVar::Const(lhs, _), rhs, false) => {
638        //         let rhs: Var<C::N> = self.builder.eval(rhs);
639        //         IfCondition::NeI(rhs, lhs)
640        //     }
641        //     (SymbolicVar::Val(lhs, _), SymbolicVar::Const(rhs, _), true) => {
642        //         let lhs: Var<C::N> = self.builder.eval(lhs);
643        //         IfCondition::EqI(lhs, rhs)
644        //     }
645        //     (SymbolicVar::Val(lhs, _), SymbolicVar::Const(rhs, _), false) => {
646        //         let lhs: Var<C::N> = self.builder.eval(lhs);
647        //         IfCondition::NeI(lhs, rhs)
648        //     }
649        //     (lhs, SymbolicVar::Const(rhs, _), true) => {
650        //         let lhs: Var<C::N> = self.builder.eval(lhs);
651        //         IfCondition::EqI(lhs, rhs)
652        //     }
653        //     (lhs, SymbolicVar::Const(rhs, _), false) => {
654        //         let lhs: Var<C::N> = self.builder.eval(lhs);
655        //         IfCondition::NeI(lhs, rhs)
656        //     }
657        //     (SymbolicVar::Val(lhs, _), SymbolicVar::Val(rhs, _), true) => IfCondition::Eq(lhs,
658        // rhs),     (SymbolicVar::Val(lhs, _), SymbolicVar::Val(rhs, _), false) => {
659        //         IfCondition::Ne(lhs, rhs)
660        //     }
661        //     (SymbolicVar::Val(lhs, _), rhs, true) => {
662        //         let rhs: Var<C::N> = self.builder.eval(rhs);
663        //         IfCondition::Eq(lhs, rhs)
664        //     }
665        //     (SymbolicVar::Val(lhs, _), rhs, false) => {
666        //         let rhs: Var<C::N> = self.builder.eval(rhs);
667        //         IfCondition::Ne(lhs, rhs)
668        //     }
669        //     (lhs, SymbolicVar::Val(rhs, _), true) => {
670        //         let lhs: Var<C::N> = self.builder.eval(lhs);
671        //         IfCondition::Eq(lhs, rhs)
672        //     }
673        //     (lhs, SymbolicVar::Val(rhs, _), false) => {
674        //         let lhs: Var<C::N> = self.builder.eval(lhs);
675        //         IfCondition::Ne(lhs, rhs)
676        //     }
677        //     (lhs, rhs, true) => {
678        //         let lhs: Var<C::N> = self.builder.eval(lhs);
679        //         let rhs: Var<C::N> = self.builder.eval(rhs);
680        //         IfCondition::Eq(lhs, rhs)
681        //     }
682        //     (lhs, rhs, false) => {
683        //         let lhs: Var<C::N> = self.builder.eval(lhs);
684        //         let rhs: Var<C::N> = self.builder.eval(rhs);
685        //         IfCondition::Ne(lhs, rhs)
686        //     }
687        // }
688    }
689}
690
691/// A builder for the DSL that handles for loops.
692pub struct RangeBuilder<'a, C: Config> {
693    start: Usize<C::N>,
694    end: Usize<C::N>,
695    step_size: usize,
696    builder: &'a mut Builder<C>,
697}
698
699impl<C: Config> RangeBuilder<'_, C> {
700    pub const fn step_by(mut self, step_size: usize) -> Self {
701        self.step_size = step_size;
702        self
703    }
704
705    pub fn for_each(self, mut f: impl FnMut(Var<C::N>, &mut Builder<C>)) {
706        let step_size = C::N::from_canonical_usize(self.step_size);
707        let loop_variable: Var<C::N> = self.builder.uninit();
708        let mut loop_body_builder = Builder::<C>::new_sub_builder(
709            self.builder.variable_count(),
710            self.builder.nb_public_values,
711            self.builder.p2_hash_num,
712            self.builder.debug,
713            self.builder.program_type,
714        );
715
716        f(loop_variable, &mut loop_body_builder);
717        self.builder.p2_hash_num = loop_body_builder.p2_hash_num;
718
719        let loop_instructions = loop_body_builder.into_operations();
720
721        let op = DslIr::For(Box::new((
722            self.start,
723            self.end,
724            step_size,
725            loop_variable,
726            loop_instructions,
727        )));
728        self.builder.push_op(op);
729    }
730}