@@ -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 } ;
@@ -106,7 +107,7 @@ pub fn const_folding(
106
107
} ,
107
108
}
108
109
let block = & mut lowered. blocks [ BlockId ( block_id) ] ;
109
- let mut additional_consts = vec ! [ ] ;
110
+ let mut additional_stmts = vec ! [ ] ;
110
111
for stmt in block. statements . iter_mut ( ) {
111
112
ctx. maybe_replace_inputs ( stmt. inputs_mut ( ) ) ;
112
113
match stmt {
@@ -141,9 +142,9 @@ pub fn const_folding(
141
142
}
142
143
Statement :: Call ( call_stmt) => {
143
144
if let Some ( updated_stmt) =
144
- ctx. handle_statement_call ( call_stmt, & mut additional_consts )
145
+ ctx. handle_statement_call ( call_stmt, & mut additional_stmts )
145
146
{
146
- * stmt = Statement :: Const ( updated_stmt) ;
147
+ * stmt = updated_stmt;
147
148
}
148
149
}
149
150
Statement :: StructConstruct ( StatementStructConstruct { inputs, output } ) => {
@@ -214,7 +215,7 @@ pub fn const_folding(
214
215
}
215
216
}
216
217
}
217
- block. statements . splice ( 0 ..0 , additional_consts . into_iter ( ) . map ( Statement :: Const ) ) ;
218
+ block. statements . splice ( 0 ..0 , additional_stmts ) ;
218
219
219
220
match & mut block. end {
220
221
FlatBlockEnd :: Goto ( _, remappings) => {
@@ -280,15 +281,15 @@ impl ConstFoldingContext<'_> {
280
281
/// Handles a statement call.
281
282
///
282
283
/// Returns None if no additional changes are required.
283
- /// If changes are required, returns an updated const- statement (to override the current
284
+ /// If changes are required, returns an updated statement (to override the current
284
285
/// statement).
285
- /// May add an additional const to `additional_consts ` if just replacing the current statement
286
+ /// May add additional statements to `additional_stmts ` if just replacing the current statement
286
287
/// is not enough.
287
288
fn handle_statement_call (
288
289
& mut self ,
289
290
stmt : & mut StatementCall ,
290
- additional_consts : & mut Vec < StatementConst > ,
291
- ) -> Option < StatementConst > {
291
+ additional_stmts : & mut Vec < Statement > ,
292
+ ) -> Option < Statement > {
292
293
let db = self . db ;
293
294
if stmt. function == self . panic_with_felt252 {
294
295
let val = self . as_const ( stmt. inputs [ 0 ] . var_id ) ?;
@@ -297,6 +298,67 @@ impl ConstFoldingContext<'_> {
297
298
. concretize ( db, vec ! [ GenericArgumentId :: Constant ( val. clone( ) . intern( db) ) ] )
298
299
. lowered ( db) ;
299
300
return None ;
301
+ } else if stmt. function == self . panic_with_byte_array {
302
+ let snap = self . var_info . get ( & stmt. inputs [ 0 ] . var_id ) ?;
303
+ let bytearray = try_extract_matches ! ( snap, VarInfo :: Snapshot ) ?;
304
+ let [
305
+ Some ( VarInfo :: Array ( data) ) ,
306
+ Some ( VarInfo :: Const ( ConstValue :: Int ( pending_word, _) ) ) ,
307
+ Some ( VarInfo :: Const ( ConstValue :: Int ( pending_len, _) ) ) ,
308
+ ] = & try_extract_matches ! ( bytearray. as_ref( ) , VarInfo :: Struct ) ?[ ..]
309
+ else {
310
+ return None ;
311
+ } ;
312
+ let mut panic_data =
313
+ vec ! [ BigInt :: from_str_radix( BYTE_ARRAY_MAGIC , 16 ) . unwrap( ) , data. len( ) . into( ) ] ;
314
+ for word in data {
315
+ let Some ( VarInfo :: Const ( ConstValue :: Int ( word, _) ) ) = word else {
316
+ continue ;
317
+ } ;
318
+ panic_data. push ( word. clone ( ) ) ;
319
+ }
320
+ panic_data. extend ( [ pending_word. clone ( ) , pending_len. clone ( ) ] ) ;
321
+ let felt252_ty = self . felt252 ;
322
+ let location = stmt. location ;
323
+ let new_var = |ty| Variable :: new ( db, ImplLookupContext :: default ( ) , ty, location) ;
324
+ let as_usage = |var_id| VarUsage { var_id, location } ;
325
+ let array_fn = |extern_id| {
326
+ let args = vec ! [ GenericArgumentId :: Type ( felt252_ty) ] ;
327
+ GenericFunctionId :: Extern ( extern_id) . concretize ( db, args) . lowered ( db)
328
+ } ;
329
+ let call_stmt = |function, inputs, outputs| {
330
+ let with_coupon = false ;
331
+ Statement :: Call ( StatementCall { function, inputs, with_coupon, outputs, location } )
332
+ } ;
333
+ let arr_var = new_var ( corelib:: core_array_felt252_ty ( db) ) ;
334
+ let mut arr = self . variables . alloc ( arr_var. clone ( ) ) ;
335
+ additional_stmts. push ( call_stmt ( array_fn ( self . array_new ) , vec ! [ ] , vec ! [ arr] ) ) ;
336
+ let felt252_var = new_var ( felt252_ty) ;
337
+ let arr_append_fn = array_fn ( self . array_append ) ;
338
+ for word in panic_data {
339
+ let to_append = self . variables . alloc ( felt252_var. clone ( ) ) ;
340
+ let new_arr = self . variables . alloc ( arr_var. clone ( ) ) ;
341
+ additional_stmts. push ( Statement :: Const ( StatementConst {
342
+ value : ConstValue :: Int ( word, felt252_ty) ,
343
+ output : to_append,
344
+ } ) ) ;
345
+ additional_stmts. push ( call_stmt (
346
+ arr_append_fn,
347
+ vec ! [ as_usage( arr) , as_usage( to_append) ] ,
348
+ vec ! [ new_arr] ,
349
+ ) ) ;
350
+ arr = new_arr;
351
+ }
352
+ let panic_ty = corelib:: get_core_ty_by_name ( db, "Panic" . into ( ) , vec ! [ ] ) ;
353
+ let panic_var = self . variables . alloc ( new_var ( panic_ty) ) ;
354
+ additional_stmts. push ( Statement :: StructConstruct ( StatementStructConstruct {
355
+ inputs : vec ! [ ] ,
356
+ output : panic_var,
357
+ } ) ) ;
358
+ return Some ( Statement :: StructConstruct ( StatementStructConstruct {
359
+ inputs : vec ! [ as_usage( panic_var) , as_usage( arr) ] ,
360
+ output : stmt. outputs [ 0 ] ,
361
+ } ) ) ;
300
362
}
301
363
let ( id, _generic_args) = stmt. function . get_extern ( db) ?;
302
364
if id == self . felt_sub {
@@ -325,7 +387,7 @@ impl ConstFoldingContext<'_> {
325
387
} else if self . div_rem_fns . contains ( & id) {
326
388
let lhs = self . as_int ( stmt. inputs [ 0 ] . var_id ) ;
327
389
if lhs. map ( Zero :: is_zero) . unwrap_or_default ( ) {
328
- additional_consts . push ( self . propagate_zero_and_get_statement ( stmt. outputs [ 1 ] ) ) ;
390
+ additional_stmts . push ( self . propagate_zero_and_get_statement ( stmt. outputs [ 1 ] ) ) ;
329
391
return Some ( self . propagate_zero_and_get_statement ( stmt. outputs [ 0 ] ) ) ;
330
392
}
331
393
let rhs = self . as_int ( stmt. inputs [ 1 ] . var_id ) ?;
@@ -336,8 +398,9 @@ impl ConstFoldingContext<'_> {
336
398
let r_output = stmt. outputs [ 1 ] ;
337
399
let r_value = ConstValue :: Int ( r, self . variables [ r_output] . ty ) ;
338
400
self . var_info . insert ( r_output, VarInfo :: Const ( r_value. clone ( ) ) ) ;
339
- additional_consts. push ( StatementConst { value : r_value, output : r_output } ) ;
340
- Some ( StatementConst { value : q_value, output : q_output } )
401
+ additional_stmts
402
+ . push ( Statement :: Const ( StatementConst { value : r_value, output : r_output } ) ) ;
403
+ Some ( Statement :: Const ( StatementConst { value : q_value, output : q_output } ) )
341
404
} else if id == self . storage_base_address_from_felt252 {
342
405
let input_var = stmt. inputs [ 0 ] . var_id ;
343
406
if let Some ( ConstValue :: Int ( val, ty) ) = self . as_const ( input_var) {
@@ -358,17 +421,20 @@ impl ConstFoldingContext<'_> {
358
421
_ => None ,
359
422
} ;
360
423
self . var_info . insert ( stmt. outputs [ 0 ] , VarInfo :: Box ( var_info. into ( ) ) ) ;
361
- Some ( StatementConst {
424
+ Some ( Statement :: Const ( StatementConst {
362
425
value : ConstValue :: Boxed ( const_value?. into ( ) ) ,
363
426
output : stmt. outputs [ 0 ] ,
364
- } )
427
+ } ) )
365
428
} else if id == self . unbox {
366
429
if let VarInfo :: Box ( inner) = self . var_info . get ( & stmt. inputs [ 0 ] . var_id ) ? {
367
430
let inner = inner. as_ref ( ) . clone ( ) ;
368
431
if let VarInfo :: Const ( inner) =
369
432
self . var_info . entry ( stmt. outputs [ 0 ] ) . insert_entry ( inner) . get ( )
370
433
{
371
- return Some ( StatementConst { value : inner. clone ( ) , output : stmt. outputs [ 0 ] } ) ;
434
+ return Some ( Statement :: Const ( StatementConst {
435
+ value : inner. clone ( ) ,
436
+ output : stmt. outputs [ 0 ] ,
437
+ } ) ) ;
372
438
}
373
439
}
374
440
None
@@ -377,7 +443,7 @@ impl ConstFoldingContext<'_> {
377
443
let output = stmt. outputs [ 0 ] ;
378
444
let value = ConstValue :: Int ( int_value. clone ( ) , self . variables [ output] . ty ) ;
379
445
self . var_info . insert ( output, VarInfo :: Const ( value. clone ( ) ) ) ;
380
- Some ( StatementConst { value, output } )
446
+ Some ( Statement :: Const ( StatementConst { value, output } ) )
381
447
} else if id == self . array_new {
382
448
self . var_info . insert ( stmt. outputs [ 0 ] , VarInfo :: Array ( vec ! [ ] ) ) ;
383
449
None
@@ -413,17 +479,17 @@ impl ConstFoldingContext<'_> {
413
479
value : BigInt ,
414
480
output : VariableId ,
415
481
nz_ty : bool ,
416
- ) -> StatementConst {
482
+ ) -> Statement {
417
483
let mut value = ConstValue :: Int ( value, self . variables [ output] . ty ) ;
418
484
if nz_ty {
419
485
value = ConstValue :: NonZero ( Box :: new ( value) ) ;
420
486
}
421
487
self . var_info . insert ( output, VarInfo :: Const ( value. clone ( ) ) ) ;
422
- StatementConst { value, output }
488
+ Statement :: Const ( StatementConst { value, output } )
423
489
}
424
490
425
491
/// Adds 0 const to `var_info` and return a const statement for it.
426
- fn propagate_zero_and_get_statement ( & mut self , output : VariableId ) -> StatementConst {
492
+ fn propagate_zero_and_get_statement ( & mut self , output : VariableId ) -> Statement {
427
493
self . propagate_const_and_get_statement ( BigInt :: zero ( ) , output, false )
428
494
}
429
495
@@ -603,11 +669,7 @@ impl ConstFoldingContext<'_> {
603
669
let arm_idx = if value < & constrain_value { 0 } else { 1 } ;
604
670
let output = info. arms [ arm_idx] . var_ids [ 0 ] ;
605
671
Some ( (
606
- vec ! [ Statement :: Const ( self . propagate_const_and_get_statement(
607
- value. clone( ) ,
608
- output,
609
- nz_ty,
610
- ) ) ] ,
672
+ vec ! [ self . propagate_const_and_get_statement( value. clone( ) , output, nz_ty) ] ,
611
673
FlatBlockEnd :: Goto ( info. arms [ arm_idx] . block_id , Default :: default ( ) ) ,
612
674
) )
613
675
} else if id == self . array_get {
@@ -822,6 +884,8 @@ pub struct ConstFoldingLibfuncInfo {
822
884
panic_with_felt252 : FunctionId ,
823
885
/// The `core::panic_with_const_felt252` function.
824
886
panic_with_const_felt252 : FreeFunctionId ,
887
+ /// The `core::panics::panic_with_byte_array` function.
888
+ panic_with_byte_array : FunctionId ,
825
889
/// Type ranges.
826
890
type_value_ranges : OrderedHashMap < TypeId , TypeInfo > ,
827
891
/// The info used for semantic const calculation.
@@ -934,6 +998,10 @@ impl ConstFoldingLibfuncInfo {
934
998
. generic_function_id ( "storage_base_address_const" ) ,
935
999
panic_with_felt252 : core. function_id ( "panic_with_felt252" , vec ! [ ] ) . lowered ( db) ,
936
1000
panic_with_const_felt252 : core. free_function_id ( "panic_with_const_felt252" ) ,
1001
+ panic_with_byte_array : core
1002
+ . submodule ( "panics" )
1003
+ . function_id ( "panic_with_byte_array" , vec ! [ ] )
1004
+ . lowered ( db) ,
937
1005
type_value_ranges,
938
1006
const_calculation_info : db. const_calc_info ( ) ,
939
1007
}
0 commit comments