@@ -10,6 +10,7 @@ use cairo_lang_semantic::items::constant::{ConstCalcInfo, ConstValue};
10
10
use cairo_lang_semantic:: items:: functions:: { GenericFunctionId , GenericFunctionWithBodyId } ;
11
11
use cairo_lang_semantic:: items:: imp:: ImplLookupContext ;
12
12
use cairo_lang_semantic:: { GenericArgumentId , MatchArmSelector , TypeId , TypeLongId , corelib} ;
13
+ use cairo_lang_utils:: byte_array:: BYTE_ARRAY_MAGIC ;
13
14
use cairo_lang_utils:: ordered_hash_map:: OrderedHashMap ;
14
15
use cairo_lang_utils:: ordered_hash_set:: OrderedHashSet ;
15
16
use cairo_lang_utils:: unordered_hash_map:: UnorderedHashMap ;
@@ -18,8 +19,8 @@ use id_arena::Arena;
18
19
use itertools:: { chain, zip_eq} ;
19
20
use num_bigint:: BigInt ;
20
21
use num_integer:: Integer ;
21
- use num_traits:: Zero ;
22
22
use num_traits:: cast:: ToPrimitive ;
23
+ use num_traits:: { Num , Zero } ;
23
24
24
25
use crate :: db:: LoweringGroup ;
25
26
use crate :: ids:: { ConcreteFunctionWithBodyId , FunctionId , SemanticFunctionIdEx } ;
@@ -105,7 +106,7 @@ pub fn const_folding(
105
106
} ,
106
107
}
107
108
let block = & mut lowered. blocks [ BlockId ( block_id) ] ;
108
- let mut additional_consts = vec ! [ ] ;
109
+ let mut additional_stmts = vec ! [ ] ;
109
110
for stmt in block. statements . iter_mut ( ) {
110
111
ctx. maybe_replace_inputs ( stmt. inputs_mut ( ) ) ;
111
112
match stmt {
@@ -140,9 +141,9 @@ pub fn const_folding(
140
141
}
141
142
Statement :: Call ( call_stmt) => {
142
143
if let Some ( updated_stmt) =
143
- ctx. handle_statement_call ( call_stmt, & mut additional_consts )
144
+ ctx. handle_statement_call ( call_stmt, & mut additional_stmts )
144
145
{
145
- * stmt = Statement :: Const ( updated_stmt) ;
146
+ * stmt = updated_stmt;
146
147
}
147
148
}
148
149
Statement :: StructConstruct ( StatementStructConstruct { inputs, output } ) => {
@@ -213,7 +214,7 @@ pub fn const_folding(
213
214
}
214
215
}
215
216
}
216
- block. statements . splice ( 0 ..0 , additional_consts . into_iter ( ) . map ( Statement :: Const ) ) ;
217
+ block. statements . splice ( 0 ..0 , additional_stmts ) ;
217
218
218
219
match & mut block. end {
219
220
FlatBlockEnd :: Goto ( _, remappings) => {
@@ -279,15 +280,15 @@ impl ConstFoldingContext<'_> {
279
280
/// Handles a statement call.
280
281
///
281
282
/// Returns None if no additional changes are required.
282
- /// If changes are required, returns an updated const- statement (to override the current
283
+ /// If changes are required, returns an updated statement (to override the current
283
284
/// statement).
284
- /// May add an additional const to `additional_consts ` if just replacing the current statement
285
+ /// May add additional statements to `additional_stmts ` if just replacing the current statement
285
286
/// is not enough.
286
287
fn handle_statement_call (
287
288
& mut self ,
288
289
stmt : & mut StatementCall ,
289
- additional_consts : & mut Vec < StatementConst > ,
290
- ) -> Option < StatementConst > {
290
+ additional_stmts : & mut Vec < Statement > ,
291
+ ) -> Option < Statement > {
291
292
let db = self . db ;
292
293
if stmt. function == self . panic_with_felt252 {
293
294
let val = self . as_const ( stmt. inputs [ 0 ] . var_id ) ?;
@@ -296,6 +297,67 @@ impl ConstFoldingContext<'_> {
296
297
. concretize ( db, vec ! [ GenericArgumentId :: Constant ( val. clone( ) . intern( db) ) ] )
297
298
. lowered ( db) ;
298
299
return None ;
300
+ } else if stmt. function == self . panic_with_byte_array {
301
+ let snap = self . var_info . get ( & stmt. inputs [ 0 ] . var_id ) ?;
302
+ let bytearray = try_extract_matches ! ( snap, VarInfo :: Snapshot ) ?;
303
+ let [
304
+ Some ( VarInfo :: Array ( data) ) ,
305
+ Some ( VarInfo :: Const ( ConstValue :: Int ( pending_word, _) ) ) ,
306
+ Some ( VarInfo :: Const ( ConstValue :: Int ( pending_len, _) ) ) ,
307
+ ] = & try_extract_matches ! ( bytearray. as_ref( ) , VarInfo :: Struct ) ?[ ..]
308
+ else {
309
+ return None ;
310
+ } ;
311
+ let mut panic_data =
312
+ vec ! [ BigInt :: from_str_radix( BYTE_ARRAY_MAGIC , 16 ) . unwrap( ) , data. len( ) . into( ) ] ;
313
+ for word in data {
314
+ let VarInfo :: Const ( ConstValue :: Int ( word, _) ) = word else {
315
+ continue ;
316
+ } ;
317
+ panic_data. push ( word. clone ( ) ) ;
318
+ }
319
+ panic_data. extend ( [ pending_word. clone ( ) , pending_len. clone ( ) ] ) ;
320
+ let felt252_ty = self . felt252 ;
321
+ let location = stmt. location ;
322
+ let new_var = |ty| Variable :: new ( db, ImplLookupContext :: default ( ) , ty, location) ;
323
+ let as_usage = |var_id| VarUsage { var_id, location } ;
324
+ let array_fn = |extern_id| {
325
+ let args = vec ! [ GenericArgumentId :: Type ( felt252_ty) ] ;
326
+ GenericFunctionId :: Extern ( extern_id) . concretize ( db, args) . lowered ( db)
327
+ } ;
328
+ let call_stmt = |function, inputs, outputs| {
329
+ let with_coupon = false ;
330
+ Statement :: Call ( StatementCall { function, inputs, with_coupon, outputs, location } )
331
+ } ;
332
+ let arr_var = new_var ( corelib:: core_array_felt252_ty ( db) ) ;
333
+ let mut arr = self . variables . alloc ( arr_var. clone ( ) ) ;
334
+ additional_stmts. push ( call_stmt ( array_fn ( self . array_new ) , vec ! [ ] , vec ! [ arr] ) ) ;
335
+ let felt252_var = new_var ( felt252_ty) ;
336
+ let arr_append_fn = array_fn ( self . array_append ) ;
337
+ for word in panic_data {
338
+ let to_append = self . variables . alloc ( felt252_var. clone ( ) ) ;
339
+ let new_arr = self . variables . alloc ( arr_var. clone ( ) ) ;
340
+ additional_stmts. push ( Statement :: Const ( StatementConst {
341
+ value : ConstValue :: Int ( word, felt252_ty) ,
342
+ output : to_append,
343
+ } ) ) ;
344
+ additional_stmts. push ( call_stmt (
345
+ arr_append_fn,
346
+ vec ! [ as_usage( arr) , as_usage( to_append) ] ,
347
+ vec ! [ new_arr] ,
348
+ ) ) ;
349
+ arr = new_arr;
350
+ }
351
+ let panic_ty = corelib:: get_core_ty_by_name ( db, "Panic" . into ( ) , vec ! [ ] ) ;
352
+ let panic_var = self . variables . alloc ( new_var ( panic_ty) ) ;
353
+ additional_stmts. push ( Statement :: StructConstruct ( StatementStructConstruct {
354
+ inputs : vec ! [ ] ,
355
+ output : panic_var,
356
+ } ) ) ;
357
+ return Some ( Statement :: StructConstruct ( StatementStructConstruct {
358
+ inputs : vec ! [ as_usage( panic_var) , as_usage( arr) ] ,
359
+ output : stmt. outputs [ 0 ] ,
360
+ } ) ) ;
299
361
}
300
362
let ( id, _generic_args) = stmt. function . get_extern ( db) ?;
301
363
if id == self . felt_sub {
@@ -324,7 +386,7 @@ impl ConstFoldingContext<'_> {
324
386
} else if self . div_rem_fns . contains ( & id) {
325
387
let lhs = self . as_int ( stmt. inputs [ 0 ] . var_id ) ;
326
388
if lhs. map ( Zero :: is_zero) . unwrap_or_default ( ) {
327
- additional_consts . push ( self . propagate_zero_and_get_statement ( stmt. outputs [ 1 ] ) ) ;
389
+ additional_stmts . push ( self . propagate_zero_and_get_statement ( stmt. outputs [ 1 ] ) ) ;
328
390
return Some ( self . propagate_zero_and_get_statement ( stmt. outputs [ 0 ] ) ) ;
329
391
}
330
392
let rhs = self . as_int ( stmt. inputs [ 1 ] . var_id ) ?;
@@ -335,8 +397,9 @@ impl ConstFoldingContext<'_> {
335
397
let r_output = stmt. outputs [ 1 ] ;
336
398
let r_value = ConstValue :: Int ( r, self . variables [ r_output] . ty ) ;
337
399
self . var_info . insert ( r_output, VarInfo :: Const ( r_value. clone ( ) ) ) ;
338
- additional_consts. push ( StatementConst { value : r_value, output : r_output } ) ;
339
- Some ( StatementConst { value : q_value, output : q_output } )
400
+ additional_stmts
401
+ . push ( Statement :: Const ( StatementConst { value : r_value, output : r_output } ) ) ;
402
+ Some ( Statement :: Const ( StatementConst { value : q_value, output : q_output } ) )
340
403
} else if id == self . storage_base_address_from_felt252 {
341
404
let input_var = stmt. inputs [ 0 ] . var_id ;
342
405
if let Some ( ConstValue :: Int ( val, ty) ) = self . as_const ( input_var) {
@@ -357,17 +420,20 @@ impl ConstFoldingContext<'_> {
357
420
_ => None ,
358
421
} ;
359
422
self . var_info . insert ( stmt. outputs [ 0 ] , VarInfo :: Box ( var_info. into ( ) ) ) ;
360
- Some ( StatementConst {
423
+ Some ( Statement :: Const ( StatementConst {
361
424
value : ConstValue :: Boxed ( const_value?. into ( ) ) ,
362
425
output : stmt. outputs [ 0 ] ,
363
- } )
426
+ } ) )
364
427
} else if id == self . unbox {
365
428
if let VarInfo :: Box ( inner) = self . var_info . get ( & stmt. inputs [ 0 ] . var_id ) ? {
366
429
let inner = inner. as_ref ( ) . clone ( ) ;
367
430
if let VarInfo :: Const ( inner) =
368
431
self . var_info . entry ( stmt. outputs [ 0 ] ) . insert_entry ( inner) . get ( )
369
432
{
370
- return Some ( StatementConst { value : inner. clone ( ) , output : stmt. outputs [ 0 ] } ) ;
433
+ return Some ( Statement :: Const ( StatementConst {
434
+ value : inner. clone ( ) ,
435
+ output : stmt. outputs [ 0 ] ,
436
+ } ) ) ;
371
437
}
372
438
}
373
439
None
@@ -376,7 +442,7 @@ impl ConstFoldingContext<'_> {
376
442
let output = stmt. outputs [ 0 ] ;
377
443
let value = ConstValue :: Int ( int_value. clone ( ) , self . variables [ output] . ty ) ;
378
444
self . var_info . insert ( output, VarInfo :: Const ( value. clone ( ) ) ) ;
379
- Some ( StatementConst { value, output } )
445
+ Some ( Statement :: Const ( StatementConst { value, output } ) )
380
446
} else if id == self . array_new {
381
447
self . var_info . insert ( stmt. outputs [ 0 ] , VarInfo :: Array ( vec ! [ ] ) ) ;
382
448
None
@@ -409,17 +475,17 @@ impl ConstFoldingContext<'_> {
409
475
value : BigInt ,
410
476
output : VariableId ,
411
477
nz_ty : bool ,
412
- ) -> StatementConst {
478
+ ) -> Statement {
413
479
let mut value = ConstValue :: Int ( value, self . variables [ output] . ty ) ;
414
480
if nz_ty {
415
481
value = ConstValue :: NonZero ( Box :: new ( value) ) ;
416
482
}
417
483
self . var_info . insert ( output, VarInfo :: Const ( value. clone ( ) ) ) ;
418
- StatementConst { value, output }
484
+ Statement :: Const ( StatementConst { value, output } )
419
485
}
420
486
421
487
/// Adds 0 const to `var_info` and return a const statement for it.
422
- fn propagate_zero_and_get_statement ( & mut self , output : VariableId ) -> StatementConst {
488
+ fn propagate_zero_and_get_statement ( & mut self , output : VariableId ) -> Statement {
423
489
self . propagate_const_and_get_statement ( BigInt :: zero ( ) , output, false )
424
490
}
425
491
@@ -599,11 +665,7 @@ impl ConstFoldingContext<'_> {
599
665
let arm_idx = if value < & constrain_value { 0 } else { 1 } ;
600
666
let output = info. arms [ arm_idx] . var_ids [ 0 ] ;
601
667
Some ( (
602
- vec ! [ Statement :: Const ( self . propagate_const_and_get_statement(
603
- value. clone( ) ,
604
- output,
605
- nz_ty,
606
- ) ) ] ,
668
+ vec ! [ self . propagate_const_and_get_statement( value. clone( ) , output, nz_ty) ] ,
607
669
FlatBlockEnd :: Goto ( info. arms [ arm_idx] . block_id , Default :: default ( ) ) ,
608
670
) )
609
671
} else if id == self . array_get {
@@ -816,6 +878,8 @@ pub struct ConstFoldingLibfuncInfo {
816
878
panic_with_felt252 : FunctionId ,
817
879
/// The `core::panic_with_const_felt252` function.
818
880
panic_with_const_felt252 : FreeFunctionId ,
881
+ /// The `core::panics::panic_with_byte_array` function.
882
+ panic_with_byte_array : FunctionId ,
819
883
/// Type ranges.
820
884
type_value_ranges : OrderedHashMap < TypeId , TypeInfo > ,
821
885
/// The info used for semantic const calculation.
@@ -928,6 +992,10 @@ impl ConstFoldingLibfuncInfo {
928
992
. generic_function_id ( "storage_base_address_const" ) ,
929
993
panic_with_felt252 : core. function_id ( "panic_with_felt252" , vec ! [ ] ) . lowered ( db) ,
930
994
panic_with_const_felt252 : core. free_function_id ( "panic_with_const_felt252" ) ,
995
+ panic_with_byte_array : core
996
+ . submodule ( "panics" )
997
+ . function_id ( "panic_with_byte_array" , vec ! [ ] )
998
+ . lowered ( db) ,
931
999
type_value_ranges,
932
1000
const_calculation_info : db. const_calc_info ( ) ,
933
1001
}
0 commit comments