11use std:: fmt:: Display ;
22
33use cairo_lang_casm:: assembler:: AssembledCairoProgram ;
4+ use cairo_lang_casm:: casm;
45use cairo_lang_casm:: instructions:: { Instruction , InstructionBody , RetInstruction } ;
56use cairo_lang_sierra:: extensions:: ConcreteLibfunc ;
7+ use cairo_lang_sierra:: extensions:: boxing:: BoxConcreteLibfunc ;
68use cairo_lang_sierra:: extensions:: circuit:: { CircuitConcreteLibfunc , CircuitInfo , VALUE_SIZE } ;
79use cairo_lang_sierra:: extensions:: const_type:: ConstConcreteLibfunc ;
810use cairo_lang_sierra:: extensions:: core:: {
@@ -106,7 +108,7 @@ pub struct SierraToCasmConfig {
106108pub struct CairoProgram {
107109 pub instructions : Vec < Instruction > ,
108110 pub debug_info : CairoProgramDebugInfo ,
109- pub consts_info : ConstsInfo ,
111+ pub segments_info : SegmentsInfo ,
110112}
111113impl Display for CairoProgram {
112114 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
@@ -116,24 +118,35 @@ impl Display for CairoProgram {
116118 writeln ! ( f, "{instruction}; // {bytecode_offset}" ) ?;
117119 bytecode_offset += instruction. body . op_size ( ) ;
118120 }
119- for segment in self . consts_info . segments . values ( ) {
121+ for segment in self . segments_info . const_segments . values ( ) {
120122 writeln ! ( f, "ret; // {bytecode_offset}" ) ?;
121123 bytecode_offset += 1 ;
122124 for value in & segment. values {
123125 writeln ! ( f, "dw {value}; // {bytecode_offset}" ) ?;
124126 bytecode_offset += 1 ;
125127 }
126128 }
129+ for segment in self . segments_info . utility_segments . values ( ) {
130+ for instruction in & segment. instructions {
131+ writeln ! ( f, "{instruction}; // {bytecode_offset}" ) ?;
132+ bytecode_offset += instruction. body . op_size ( ) ;
133+ }
134+ }
127135 } else {
128136 for instruction in & self . instructions {
129137 writeln ! ( f, "{instruction};" ) ?;
130138 }
131- for segment in self . consts_info . segments . values ( ) {
139+ for segment in self . segments_info . const_segments . values ( ) {
132140 writeln ! ( f, "ret;" ) ?;
133141 for value in & segment. values {
134142 writeln ! ( f, "dw {value};" ) ?;
135143 }
136144 }
145+ for segment in self . segments_info . utility_segments . values ( ) {
146+ for instruction in & segment. instructions {
147+ writeln ! ( f, "{instruction};" ) ?;
148+ }
149+ }
137150 }
138151 Ok ( ( ) )
139152 }
@@ -166,10 +179,13 @@ impl CairoProgram {
166179 else {
167180 panic ! ( "`ret` instruction should be a single word." )
168181 } ;
169- for segment in self . consts_info . segments . values ( ) {
182+ for segment in self . segments_info . const_segments . values ( ) {
170183 bytecode. push ( ret_bytecode. clone ( ) ) ;
171184 bytecode. extend ( segment. values . clone ( ) ) ;
172185 }
186+ for segment in self . segments_info . utility_segments . values ( ) {
187+ bytecode. extend ( segment. instructions . iter ( ) . flat_map ( |inst| inst. assemble ( ) . encode ( ) ) ) ;
188+ }
173189 for instruction in footer {
174190 assert ! (
175191 instruction. hints. is_empty( ) ,
@@ -238,14 +254,18 @@ pub struct CairoProgramDebugInfo {
238254
239255/// The information about the constants used in the program.
240256#[ derive( Debug , Eq , PartialEq , Default , Clone ) ]
241- pub struct ConstsInfo {
242- pub segments : OrderedHashMap < u32 , ConstSegment > ,
257+ pub struct SegmentsInfo {
258+ pub const_segments : OrderedHashMap < u32 , ConstSegment > ,
243259 pub total_segments_size : usize ,
244260
245261 /// Maps a circuit to its segment id.
246262 pub circuit_segments : OrderedHashMap < ConcreteTypeId , u32 > ,
263+
264+ /// Utility segments for code reuse.
265+ pub utility_segments : OrderedHashMap < UtilityId , UtilitySegment > ,
247266}
248- impl ConstsInfo {
267+
268+ impl SegmentsInfo {
249269 /// Creates a new `ConstSegmentsInfo` from the given libfuncs.
250270 pub fn new < ' a > (
251271 program_info : & ProgramRegistryInfo ,
@@ -272,14 +292,14 @@ impl ConstsInfo {
272292 Ok ( ( ) )
273293 } ;
274294
275- let mut segments = OrderedHashMap :: default ( ) ;
295+ let mut const_segments = OrderedHashMap :: default ( ) ;
276296
277297 for id in libfunc_ids. clone ( ) {
278298 if let CoreConcreteLibfunc :: Const ( ConstConcreteLibfunc :: AsBox ( as_box) ) =
279299 program_info. registry . get_libfunc ( id) . unwrap ( )
280300 {
281301 add_const (
282- & mut segments ,
302+ & mut const_segments ,
283303 as_box. segment_id ,
284304 as_box. const_type . clone ( ) ,
285305 extract_const_value ( program_info, & as_box. const_type ) . unwrap ( ) ,
@@ -288,18 +308,18 @@ impl ConstsInfo {
288308 }
289309
290310 // Check that the segments were declared in order and without holes.
291- if segments
311+ if const_segments
292312 . keys ( )
293313 . enumerate ( )
294314 . any ( |( i, segment_id) | i != segment_id. into_or_panic :: < usize > ( ) )
295315 {
296316 return Err ( CompilationError :: ConstSegmentsOutOfOrder ) ;
297317 }
298318
299- let mut next_segment = segments . len ( ) as u32 ;
319+ let mut next_segment = const_segments . len ( ) as u32 ;
300320 let mut circuit_segments = OrderedHashMap :: default ( ) ;
301321
302- for id in libfunc_ids {
322+ for id in libfunc_ids. clone ( ) {
303323 if let CoreConcreteLibfunc :: Circuit ( CircuitConcreteLibfunc :: GetDescriptor ( libfunc) ) =
304324 program_info. registry . get_libfunc ( id) . unwrap ( )
305325 {
@@ -314,19 +334,50 @@ impl ConstsInfo {
314334 push_offset ( gate_offsets. output ) ;
315335 }
316336
317- add_const ( & mut segments , next_segment, circ_ty. clone ( ) , const_value) ?;
337+ add_const ( & mut const_segments , next_segment, circ_ty. clone ( ) , const_value) ?;
318338 circuit_segments. insert ( circ_ty. clone ( ) , next_segment) ;
319339 next_segment += 1 ;
320340 }
321341 }
322342
343+ let mut utility_instructions = Vec :: default ( ) ;
344+
345+ // Check for BoxFromTempStore usage
346+ let has_box_from_temp_store = libfunc_ids. into_iter ( ) . any ( |id| {
347+ matches ! (
348+ program_info. registry. get_libfunc( id) ,
349+ Ok ( CoreConcreteLibfunc :: Box ( BoxConcreteLibfunc :: FromTempStore ( _) ) )
350+ )
351+ } ) ;
352+
353+ if has_box_from_temp_store {
354+ utility_instructions. push ( (
355+ UtilityId :: BoxFromTempStore ,
356+ casm ! {
357+ call rel 2 ;
358+ ret;
359+ }
360+ . instructions ,
361+ ) ) ;
362+ }
363+
323364 let mut total_segments_size = 0 ;
324- for ( _, segment) in segments . iter_mut ( ) {
365+ for ( _, segment) in const_segments . iter_mut ( ) {
325366 segment. segment_offset = total_segments_size;
326367 // Add 1 for the `ret` instruction.
327368 total_segments_size += 1 + segment. values . len ( ) ;
328369 }
329- Ok ( Self { segments, total_segments_size, circuit_segments } )
370+
371+ let utility_segments = utility_instructions
372+ . into_iter ( )
373+ . map ( |( id, instructions) | {
374+ let segment = UtilitySegment { instructions, offset : total_segments_size } ;
375+ total_segments_size +=
376+ segment. instructions . iter ( ) . map ( |i| i. body . op_size ( ) ) . sum :: < usize > ( ) ;
377+ ( id, segment)
378+ } )
379+ . collect ( ) ;
380+ Ok ( Self { const_segments, total_segments_size, circuit_segments, utility_segments } )
330381 }
331382}
332383
@@ -341,6 +392,20 @@ pub struct ConstSegment {
341392 pub segment_offset : usize ,
342393}
343394
395+ /// The data for a single utility segment (code).
396+ #[ derive( Debug , Eq , PartialEq , Default , Clone ) ]
397+ pub struct UtilitySegment {
398+ /// The instructions in the segment.
399+ pub instructions : Vec < Instruction > ,
400+ /// Offset from start of segments
401+ pub offset : usize ,
402+ }
403+
404+ #[ derive( Debug , Eq , PartialEq , Hash , Clone ) ]
405+ pub enum UtilityId {
406+ BoxFromTempStore ,
407+ }
408+
344409/// Gets a concrete type, if it is a const type returns a vector of the values to be stored in the
345410/// const segment.
346411fn extract_const_value (
@@ -639,17 +704,17 @@ pub fn compile(
639704 . max_bytecode_size
640705 . checked_sub ( program_offset)
641706 . ok_or_else ( || Box :: new ( CompilationError :: CodeSizeLimitExceeded ) ) ?;
642- let consts_info = ConstsInfo :: new (
707+ let segments_info = SegmentsInfo :: new (
643708 program_info,
644709 program. libfunc_declarations . iter ( ) . map ( |ld| & ld. id ) ,
645710 & circuits_info. circuits ,
646711 const_segments_max_size,
647712 ) ?;
648- relocate_instructions ( & relocations, & statement_offsets, & consts_info , & mut instructions) ;
713+ relocate_instructions ( & relocations, & statement_offsets, & segments_info , & mut instructions) ;
649714
650715 Ok ( CairoProgram {
651716 instructions,
652- consts_info ,
717+ segments_info ,
653718 debug_info : CairoProgramDebugInfo { sierra_statement_info } ,
654719 } )
655720}
0 commit comments