@@ -7,7 +7,7 @@ use crate::{
77 error:: { Result , SierraAssertError } ,
88 libfuncs:: r#struct:: build_struct_value,
99 metadata:: MetadataStorage ,
10- types:: TypeBuilder ,
10+ types:: { circuit :: build_u384_struct_type , TypeBuilder } ,
1111 utils:: { get_integer_layout, layout_repeat, BlockExt , ProgramRegistryExt } ,
1212} ;
1313use cairo_lang_sierra:: {
@@ -28,8 +28,8 @@ use melior::{
2828 cf, llvm,
2929 } ,
3030 ir:: {
31- attribute:: DenseI32ArrayAttribute , r#type:: IntegerType , Block , BlockLike , Location , Value ,
32- ValueLike ,
31+ attribute:: DenseI32ArrayAttribute , r#type:: IntegerType , Block , BlockLike , Location , Type ,
32+ Value , ValueLike ,
3333 } ,
3434 Context ,
3535} ;
@@ -70,6 +70,9 @@ pub fn build<'ctx, 'this>(
7070 signature,
7171 ..
7272 } )
73+ | CircuitConcreteLibfunc :: U96SingleLimbLessThanGuaranteeVerify (
74+ SignatureOnlyConcreteLibfunc { signature, .. } ,
75+ )
7376 | CircuitConcreteLibfunc :: U96GuaranteeVerify ( SignatureOnlyConcreteLibfunc { signature } ) => {
7477 super :: build_noop :: < 1 , true > (
7578 context,
@@ -86,11 +89,6 @@ pub fn build<'ctx, 'this>(
8689 context, registry, entry, location, helper, metadata, info,
8790 )
8891 }
89- CircuitConcreteLibfunc :: U96SingleLimbLessThanGuaranteeVerify ( info) => {
90- build_u96_single_limb_less_than_guarantee_verify (
91- context, registry, entry, location, helper, metadata, info,
92- )
93- }
9492 }
9593}
9694
@@ -373,7 +371,6 @@ fn build_eval<'ctx, 'this>(
373371 // let zero = entry.argument(5)?;
374372 // let one = entry.argument(6)?;
375373
376- // We multiply the amount of gates evaluated by 4 (the amount of u96s in each gate)
377374 let add_mod = increment_builtin_counter_by (
378375 context,
379376 entry,
@@ -402,6 +399,21 @@ fn build_eval<'ctx, 'this>(
402399 circuit_info. mul_offsets . len ( ) * MOD_BUILTIN_INSTANCE_SIZE ,
403400 ) ?;
404401
402+ // convert circuit output from integer representation to struct representation
403+ let gates = gates
404+ . into_iter ( )
405+ . map ( |value| u384_integer_to_struct ( context, ok_block, location, value) )
406+ . collect :: < Result < Vec < _ > > > ( ) ?;
407+
408+ let n_gates = circuit_info. values . len ( ) ;
409+ let gates_array = ok_block. append_op_result ( llvm:: undef (
410+ llvm:: r#type:: array ( build_u384_struct_type ( context) , n_gates as u32 ) ,
411+ location,
412+ ) ) ?;
413+ let gates_array = ok_block. insert_values ( context, location, gates_array, & gates) ?;
414+
415+ let modulus_struct = u384_integer_to_struct ( context, ok_block, location, circuit_modulus) ?;
416+
405417 // Build output struct
406418 let outputs_type_id = & info. branch_signatures ( ) [ 0 ] . vars [ 2 ] . ty ;
407419 let outputs = build_struct_value (
@@ -412,7 +424,7 @@ fn build_eval<'ctx, 'this>(
412424 helper,
413425 metadata,
414426 outputs_type_id,
415- & gates ,
427+ & [ gates_array , modulus_struct ] ,
416428 ) ?;
417429
418430 ok_block. append_operation ( helper. br ( 0 , & [ add_mod, mul_mod, outputs] , location) ) ;
@@ -719,7 +731,6 @@ fn build_failure_guarantee_verify<'ctx, 'this>(
719731}
720732
721733/// Generate MLIR operations for the `u96_limbs_less_than_guarantee_verify` libfunc.
722- /// NOOP
723734#[ allow( clippy:: too_many_arguments) ]
724735fn build_u96_limbs_less_than_guarantee_verify < ' ctx , ' this > (
725736 context : & ' ctx Context ,
@@ -730,45 +741,81 @@ fn build_u96_limbs_less_than_guarantee_verify<'ctx, 'this>(
730741 metadata : & mut MetadataStorage ,
731742 info : & ConcreteU96LimbsLessThanGuaranteeVerifyLibfunc ,
732743) -> Result < ( ) > {
733- let guarantee_type_id = & info . branch_signatures ( ) [ 0 ] . vars [ 0 ] . ty ;
734- let guarantee_type = registry . build_type ( context , helper , metadata , guarantee_type_id ) ? ;
744+ let guarantee = entry . arg ( 0 ) ? ;
745+ let limb_count = info . limb_count ;
735746
736- let guarantee = entry. append_op_result ( llvm:: undef ( guarantee_type, location) ) ?;
747+ let u96_type = IntegerType :: new ( context, 96 ) . into ( ) ;
748+ let limb_struct_type = llvm:: r#type:: r#struct ( context, & vec ! [ u96_type; limb_count] , false ) ;
749+
750+ // extract gate and modulus from input value
751+ let gate = entry. extract_value ( context, location, guarantee, limb_struct_type, 0 ) ?;
752+ let modulus = entry. extract_value ( context, location, guarantee, limb_struct_type, 1 ) ?;
737753
738- let u96_type_id = & info. branch_signatures ( ) [ 1 ] . vars [ 0 ] . ty ;
739- let u96_type = registry. build_type ( context, helper, metadata, u96_type_id) ?;
754+ // extract last limb from gate and modulus
755+ let gate_last_limb = entry. extract_value ( context, location, gate, u96_type, limb_count - 1 ) ?;
756+ let modulus_last_limb =
757+ entry. extract_value ( context, location, modulus, u96_type, limb_count - 1 ) ?;
740758
741- let u96 = entry. append_op_result ( llvm:: undef ( u96_type, location) ) ?;
759+ // calcualte diff between limbs
760+ let diff = entry. append_op_result ( arith:: subi ( modulus_last_limb, gate_last_limb, location) ) ?;
761+ let k0 = entry. const_int_from_type ( context, location, 0 , u96_type) ?;
762+ let has_diff = entry. cmpi ( context, CmpiPredicate :: Ne , diff, k0, location) ?;
742763
743- let kfalse = entry. const_int ( context, location, 0 , 64 ) ?;
744- entry. append_operation ( helper. cond_br (
764+ let diff_block = helper. append_block ( Block :: new ( & [ ] ) ) ;
765+ let next_block = helper. append_block ( Block :: new ( & [ ] ) ) ;
766+ entry. append_operation ( cf:: cond_br (
745767 context,
746- kfalse,
747- [ 0 , 1 ] ,
748- [ & [ guarantee] , & [ u96] ] ,
768+ has_diff,
769+ diff_block,
770+ next_block,
771+ & [ ] ,
772+ & [ ] ,
749773 location,
750774 ) ) ;
751775
752- Ok ( ( ) )
753- }
776+ {
777+ // if there is diff, return it
778+ diff_block. append_operation ( helper. br ( 1 , & [ diff] , location) ) ;
779+ }
780+ {
781+ // if there is no diff, build a new guarantee, skipping last limb
782+ let new_limb_struct_type =
783+ llvm:: r#type:: r#struct ( context, & vec ! [ u96_type; limb_count - 1 ] , false ) ;
784+ let new_gate = build_array_slice (
785+ context,
786+ next_block,
787+ location,
788+ gate,
789+ u96_type,
790+ new_limb_struct_type,
791+ 0 ,
792+ limb_count - 1 ,
793+ ) ?;
794+ let new_modulus = build_array_slice (
795+ context,
796+ next_block,
797+ location,
798+ modulus,
799+ u96_type,
800+ new_limb_struct_type,
801+ 0 ,
802+ limb_count - 1 ,
803+ ) ?;
754804
755- /// Generate MLIR operations for the `u96_single_limb_less_than_guarantee_verify` libfunc.
756- /// NOOP
757- #[ allow( clippy:: too_many_arguments) ]
758- fn build_u96_single_limb_less_than_guarantee_verify < ' ctx , ' this > (
759- context : & ' ctx Context ,
760- registry : & ProgramRegistry < CoreType , CoreLibfunc > ,
761- entry : & ' this Block < ' ctx > ,
762- location : Location < ' ctx > ,
763- helper : & LibfuncHelper < ' ctx , ' this > ,
764- metadata : & mut MetadataStorage ,
765- info : & SignatureOnlyConcreteLibfunc ,
766- ) -> Result < ( ) > {
767- let u96_type_id = & info. branch_signatures ( ) [ 0 ] . vars [ 0 ] . ty ;
768- let u96_type = registry. build_type ( context, helper, metadata, u96_type_id) ?;
769- let u96 = entry. append_op_result ( llvm:: undef ( u96_type, location) ) ?;
805+ let guarantee_type_id = & info. branch_signatures ( ) [ 0 ] . vars [ 0 ] . ty ;
806+ let new_guarantee = build_struct_value (
807+ context,
808+ registry,
809+ next_block,
810+ location,
811+ helper,
812+ metadata,
813+ guarantee_type_id,
814+ & [ new_gate, new_modulus] ,
815+ ) ?;
770816
771- entry. append_operation ( helper. br ( 0 , & [ u96] , location) ) ;
817+ next_block. append_operation ( helper. br ( 0 , & [ new_guarantee] , location) ) ;
818+ }
772819
773820 Ok ( ( ) )
774821}
@@ -798,18 +845,41 @@ fn build_get_output<'ctx, 'this>(
798845 let output_idx = output_offset_idx - circuit_info. n_inputs - 1 ;
799846
800847 let outputs = entry. arg ( 0 ) ?;
801- let output_integer = entry. extract_value (
848+
849+ let n_gates = circuit_info. values . len ( ) ;
850+ let output_gates = entry. extract_value (
802851 context,
803852 location,
804853 outputs,
805- IntegerType :: new ( context, 384 ) . into ( ) ,
854+ llvm:: r#type:: array ( build_u384_struct_type ( context) , n_gates as u32 ) ,
855+ 0 ,
856+ ) ?;
857+ let modulus_struct = entry. extract_value (
858+ context,
859+ location,
860+ outputs,
861+ build_u384_struct_type ( context) ,
862+ 1 ,
863+ ) ?;
864+ let output_struct = entry. extract_value (
865+ context,
866+ location,
867+ output_gates,
868+ build_u384_struct_type ( context) ,
806869 output_idx,
807870 ) ?;
808- let output_struct = u384_integer_to_struct ( context, entry, location, output_integer) ?;
809871
810872 let guarantee_type_id = & info. branch_signatures ( ) [ 0 ] . vars [ 1 ] . ty ;
811- let guarantee_type = registry. build_type ( context, helper, metadata, guarantee_type_id) ?;
812- let guarantee = entry. append_op_result ( llvm:: undef ( guarantee_type, location) ) ?;
873+ let guarantee = build_struct_value (
874+ context,
875+ registry,
876+ entry,
877+ location,
878+ helper,
879+ metadata,
880+ guarantee_type_id,
881+ & [ output_struct, modulus_struct] ,
882+ ) ?;
813883
814884 entry. append_operation ( helper. br ( 0 , & [ output_struct, guarantee] , location) ) ;
815885
@@ -892,16 +962,7 @@ fn u384_integer_to_struct<'a>(
892962 block. trunci ( limb, u96_type, location) ?
893963 } ;
894964
895- let struct_type = llvm:: r#type:: r#struct (
896- context,
897- & [
898- IntegerType :: new ( context, 96 ) . into ( ) ,
899- IntegerType :: new ( context, 96 ) . into ( ) ,
900- IntegerType :: new ( context, 96 ) . into ( ) ,
901- IntegerType :: new ( context, 96 ) . into ( ) ,
902- ] ,
903- false ,
904- ) ;
965+ let struct_type = build_u384_struct_type ( context) ;
905966 let struct_value = block. append_op_result ( llvm:: undef ( struct_type, location) ) ?;
906967
907968 block. insert_values (
@@ -993,6 +1054,35 @@ fn build_euclidean_algorithm<'ctx, 'this>(
9931054 Ok ( end_block)
9941055}
9951056
1057+ /// Extracts values from indexes `from` - `to` (exclusive) and builds a new value of type `result_type`
1058+ ///
1059+ /// Can be used with arrays, or structs with multiple elements of a single type.
1060+ #[ allow( clippy:: too_many_arguments) ]
1061+ fn build_array_slice < ' ctx > (
1062+ context : & ' ctx Context ,
1063+ block : & ' ctx Block < ' ctx > ,
1064+ location : Location < ' ctx > ,
1065+ aggregate : Value < ' ctx , ' ctx > ,
1066+ element_type : Type < ' ctx > ,
1067+ result_type : Type < ' ctx > ,
1068+ from : usize ,
1069+ to : usize ,
1070+ ) -> Result < Value < ' ctx , ' ctx > > {
1071+ let mut values = Vec :: with_capacity ( to - from) ;
1072+
1073+ for i in from..to {
1074+ let value = block. extract_value ( context, location, aggregate, element_type, i) ?;
1075+ values. push ( value) ;
1076+ }
1077+
1078+ block. insert_values (
1079+ context,
1080+ location,
1081+ block. append_op_result ( llvm:: undef ( result_type, location) ) ?,
1082+ & values,
1083+ )
1084+ }
1085+
9961086#[ cfg( test) ]
9971087mod test {
9981088
0 commit comments