Skip to content

Commit e0aba3b

Browse files
committed
Added const-folding of panic-with-byte-array.
simplified the panic! macro as it is now ok. commit-id:8e3dc5aa
1 parent 4dd564c commit e0aba3b

File tree

6 files changed

+247
-139
lines changed

6 files changed

+247
-139
lines changed

crates/cairo-lang-lowering/src/lower/test_data/closure

+9-13
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,15 @@ Parameters: v0: test::PanicDestructable
124124
blk0 (root):
125125
Statements:
126126
(v1: {closure@lib.cairo:11:5: 11:7}) <- struct_construct(v0)
127-
(v2: core::array::Array::<core::felt252>) <- core::array::ArrayImpl::<core::felt252>::new()
128-
(v3: core::felt252) <- 1997209042069643135709344952807065910992472029923670688473712229447419591075
129-
(v5: core::array::Array::<core::felt252>, v4: ()) <- core::array::ArrayImpl::<core::felt252>::append(v2, v3)
130-
(v6: core::felt252) <- 0
131-
(v8: core::array::Array::<core::felt252>, v7: ()) <- core::array::ArrayImpl::<core::felt252>::append(v5, v6)
132-
(v9: core::felt252) <- 345232009571
133-
(v11: core::array::Array::<core::felt252>, v10: ()) <- core::array::ArrayImpl::<core::felt252>::append(v8, v9)
134-
(v12: core::felt252) <- 5
135-
(v14: core::array::Array::<core::felt252>, v13: ()) <- core::array::ArrayImpl::<core::felt252>::append(v11, v12)
136-
(v15: core::panics::Panic) <- struct_construct()
137-
(v16: (core::panics::Panic, core::array::Array::<core::felt252>)) <- struct_construct(v15, v14)
138-
End:
139-
Panic(v16)
127+
(v2: core::array::Array::<core::bytes_31::bytes31>) <- core::array::array_new::<core::bytes_31::bytes31>()
128+
(v3: core::felt252) <- 345232009571
129+
(v4: core::integer::u32) <- 5
130+
(v5: core::byte_array::ByteArray) <- struct_construct(v2, v3, v4)
131+
(v6: core::byte_array::ByteArray, v7: @core::byte_array::ByteArray) <- snapshot(v5)
132+
(v8: core::never) <- core::panics::panic_with_byte_array(v7)
133+
End:
134+
Match(match_enum(v8) {
135+
})
140136

141137

142138
Final lowering:

crates/cairo-lang-lowering/src/optimizations/const_folding.rs

+92-24
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use cairo_lang_semantic::items::constant::{ConstCalcInfo, ConstValue};
1010
use cairo_lang_semantic::items::functions::{GenericFunctionId, GenericFunctionWithBodyId};
1111
use cairo_lang_semantic::items::imp::ImplLookupContext;
1212
use cairo_lang_semantic::{GenericArgumentId, MatchArmSelector, TypeId, TypeLongId, corelib};
13+
use cairo_lang_utils::byte_array::BYTE_ARRAY_MAGIC;
1314
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
1415
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
1516
use cairo_lang_utils::unordered_hash_map::UnorderedHashMap;
@@ -18,8 +19,8 @@ use id_arena::Arena;
1819
use itertools::{chain, zip_eq};
1920
use num_bigint::BigInt;
2021
use num_integer::Integer;
21-
use num_traits::Zero;
2222
use num_traits::cast::ToPrimitive;
23+
use num_traits::{Num, Zero};
2324

2425
use crate::db::LoweringGroup;
2526
use crate::ids::{ConcreteFunctionWithBodyId, FunctionId, SemanticFunctionIdEx};
@@ -105,7 +106,7 @@ pub fn const_folding(
105106
},
106107
}
107108
let block = &mut lowered.blocks[BlockId(block_id)];
108-
let mut additional_consts = vec![];
109+
let mut additional_stmts = vec![];
109110
for stmt in block.statements.iter_mut() {
110111
ctx.maybe_replace_inputs(stmt.inputs_mut());
111112
match stmt {
@@ -140,9 +141,9 @@ pub fn const_folding(
140141
}
141142
Statement::Call(call_stmt) => {
142143
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)
144145
{
145-
*stmt = Statement::Const(updated_stmt);
146+
*stmt = updated_stmt;
146147
}
147148
}
148149
Statement::StructConstruct(StatementStructConstruct { inputs, output }) => {
@@ -213,7 +214,7 @@ pub fn const_folding(
213214
}
214215
}
215216
}
216-
block.statements.splice(0..0, additional_consts.into_iter().map(Statement::Const));
217+
block.statements.splice(0..0, additional_stmts);
217218

218219
match &mut block.end {
219220
FlatBlockEnd::Goto(_, remappings) => {
@@ -279,15 +280,15 @@ impl ConstFoldingContext<'_> {
279280
/// Handles a statement call.
280281
///
281282
/// 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
283284
/// 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
285286
/// is not enough.
286287
fn handle_statement_call(
287288
&mut self,
288289
stmt: &mut StatementCall,
289-
additional_consts: &mut Vec<StatementConst>,
290-
) -> Option<StatementConst> {
290+
additional_stmts: &mut Vec<Statement>,
291+
) -> Option<Statement> {
291292
let db = self.db;
292293
if stmt.function == self.panic_with_felt252 {
293294
let val = self.as_const(stmt.inputs[0].var_id)?;
@@ -296,6 +297,67 @@ impl ConstFoldingContext<'_> {
296297
.concretize(db, vec![GenericArgumentId::Constant(val.clone().intern(db))])
297298
.lowered(db);
298299
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+
}));
299361
}
300362
let (id, _generic_args) = stmt.function.get_extern(db)?;
301363
if id == self.felt_sub {
@@ -324,7 +386,7 @@ impl ConstFoldingContext<'_> {
324386
} else if self.div_rem_fns.contains(&id) {
325387
let lhs = self.as_int(stmt.inputs[0].var_id);
326388
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]));
328390
return Some(self.propagate_zero_and_get_statement(stmt.outputs[0]));
329391
}
330392
let rhs = self.as_int(stmt.inputs[1].var_id)?;
@@ -335,8 +397,9 @@ impl ConstFoldingContext<'_> {
335397
let r_output = stmt.outputs[1];
336398
let r_value = ConstValue::Int(r, self.variables[r_output].ty);
337399
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 }))
340403
} else if id == self.storage_base_address_from_felt252 {
341404
let input_var = stmt.inputs[0].var_id;
342405
if let Some(ConstValue::Int(val, ty)) = self.as_const(input_var) {
@@ -357,17 +420,20 @@ impl ConstFoldingContext<'_> {
357420
_ => None,
358421
};
359422
self.var_info.insert(stmt.outputs[0], VarInfo::Box(var_info.into()));
360-
Some(StatementConst {
423+
Some(Statement::Const(StatementConst {
361424
value: ConstValue::Boxed(const_value?.into()),
362425
output: stmt.outputs[0],
363-
})
426+
}))
364427
} else if id == self.unbox {
365428
if let VarInfo::Box(inner) = self.var_info.get(&stmt.inputs[0].var_id)? {
366429
let inner = inner.as_ref().clone();
367430
if let VarInfo::Const(inner) =
368431
self.var_info.entry(stmt.outputs[0]).insert_entry(inner).get()
369432
{
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+
}));
371437
}
372438
}
373439
None
@@ -376,7 +442,7 @@ impl ConstFoldingContext<'_> {
376442
let output = stmt.outputs[0];
377443
let value = ConstValue::Int(int_value.clone(), self.variables[output].ty);
378444
self.var_info.insert(output, VarInfo::Const(value.clone()));
379-
Some(StatementConst { value, output })
445+
Some(Statement::Const(StatementConst { value, output }))
380446
} else if id == self.array_new {
381447
self.var_info.insert(stmt.outputs[0], VarInfo::Array(vec![]));
382448
None
@@ -409,17 +475,17 @@ impl ConstFoldingContext<'_> {
409475
value: BigInt,
410476
output: VariableId,
411477
nz_ty: bool,
412-
) -> StatementConst {
478+
) -> Statement {
413479
let mut value = ConstValue::Int(value, self.variables[output].ty);
414480
if nz_ty {
415481
value = ConstValue::NonZero(Box::new(value));
416482
}
417483
self.var_info.insert(output, VarInfo::Const(value.clone()));
418-
StatementConst { value, output }
484+
Statement::Const(StatementConst { value, output })
419485
}
420486

421487
/// 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 {
423489
self.propagate_const_and_get_statement(BigInt::zero(), output, false)
424490
}
425491

@@ -599,11 +665,7 @@ impl ConstFoldingContext<'_> {
599665
let arm_idx = if value < &constrain_value { 0 } else { 1 };
600666
let output = info.arms[arm_idx].var_ids[0];
601667
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)],
607669
FlatBlockEnd::Goto(info.arms[arm_idx].block_id, Default::default()),
608670
))
609671
} else if id == self.array_get {
@@ -816,6 +878,8 @@ pub struct ConstFoldingLibfuncInfo {
816878
panic_with_felt252: FunctionId,
817879
/// The `core::panic_with_const_felt252` function.
818880
panic_with_const_felt252: FreeFunctionId,
881+
/// The `core::panics::panic_with_byte_array` function.
882+
panic_with_byte_array: FunctionId,
819883
/// Type ranges.
820884
type_value_ranges: OrderedHashMap<TypeId, TypeInfo>,
821885
/// The info used for semantic const calculation.
@@ -928,6 +992,10 @@ impl ConstFoldingLibfuncInfo {
928992
.generic_function_id("storage_base_address_const"),
929993
panic_with_felt252: core.function_id("panic_with_felt252", vec![]).lowered(db),
930994
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),
931999
type_value_ranges,
9321000
const_calculation_info: db.const_calc_info(),
9331001
}

crates/cairo-lang-lowering/src/optimizations/test_data/const_folding

+59
Original file line numberDiff line numberDiff line change
@@ -5118,3 +5118,62 @@ End:
51185118
Return(v8)
51195119

51205120
//! > lowering_diagnostics
5121+
5122+
//! > ==========================================================================
5123+
5124+
//! > Panic with byte array value.
5125+
5126+
//! > test_runner_name
5127+
test_match_optimizer
5128+
5129+
//! > function
5130+
fn foo() {
5131+
core::panics::panic_with_byte_array(@"hello world");
5132+
}
5133+
5134+
//! > function_name
5135+
foo
5136+
5137+
//! > module_code
5138+
5139+
//! > semantic_diagnostics
5140+
5141+
//! > before
5142+
Parameters:
5143+
blk0 (root):
5144+
Statements:
5145+
(v0: core::array::Array::<core::bytes_31::bytes31>) <- core::array::array_new::<core::bytes_31::bytes31>()
5146+
(v1: core::felt252) <- 126207244316550804821666916
5147+
(v2: core::integer::u32) <- 11
5148+
(v3: core::byte_array::ByteArray) <- struct_construct(v0, v1, v2)
5149+
(v4: core::byte_array::ByteArray, v5: @core::byte_array::ByteArray) <- snapshot(v3)
5150+
(v6: (core::panics::Panic, core::array::Array::<core::felt252>)) <- core::panics::panic_with_byte_array(v5)
5151+
(v7: core::panics::PanicResult::<((),)>) <- PanicResult::Err(v6)
5152+
End:
5153+
Return(v7)
5154+
5155+
//! > after
5156+
Parameters:
5157+
blk0 (root):
5158+
Statements:
5159+
(v8: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
5160+
(v9: core::felt252) <- 1997209042069643135709344952807065910992472029923670688473712229447419591075
5161+
(v10: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v8, v9)
5162+
(v11: core::felt252) <- 0
5163+
(v12: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v10, v11)
5164+
(v13: core::felt252) <- 126207244316550804821666916
5165+
(v14: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v12, v13)
5166+
(v15: core::felt252) <- 11
5167+
(v16: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v14, v15)
5168+
(v17: core::panics::Panic) <- struct_construct()
5169+
(v0: core::array::Array::<core::bytes_31::bytes31>) <- core::array::array_new::<core::bytes_31::bytes31>()
5170+
(v1: core::felt252) <- 126207244316550804821666916
5171+
(v2: core::integer::u32) <- 11
5172+
(v3: core::byte_array::ByteArray) <- struct_construct(v0, v1, v2)
5173+
(v4: core::byte_array::ByteArray, v5: @core::byte_array::ByteArray) <- snapshot(v3)
5174+
(v6: (core::panics::Panic, core::array::Array::<core::felt252>)) <- struct_construct(v17, v16)
5175+
(v7: core::panics::PanicResult::<((),)>) <- PanicResult::Err(v6)
5176+
End:
5177+
Return(v7)
5178+
5179+
//! > lowering_diagnostics

crates/cairo-lang-semantic/src/expr/expansion_test_data/inline_macros

+4-4
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ test_expand_expr(expect_diagnostics: false)
107107
panic!()
108108

109109
//! > expanded_code
110-
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, 0, 0])
110+
core::panics::panic_with_byte_array(@"")
111111

112112
//! > diagnostics
113113

@@ -122,7 +122,7 @@ test_expand_expr(expect_diagnostics: false)
122122
panic!("0123456")
123123

124124
//! > expanded_code
125-
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, 0x30313233343536, 7])
125+
core::panics::panic_with_byte_array(@"0123456")
126126

127127
//! > diagnostics
128128

@@ -137,7 +137,7 @@ test_expand_expr(expect_diagnostics: false)
137137
panic!("0123456789012345678901234567890")
138138

139139
//! > expanded_code
140-
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 1, 0x30313233343536373839303132333435363738393031323334353637383930, 0, 0])
140+
core::panics::panic_with_byte_array(@"0123456789012345678901234567890")
141141

142142
//! > diagnostics
143143

@@ -152,7 +152,7 @@ test_expand_expr(expect_diagnostics: false)
152152
panic!("01234567890123456789012345678901234")
153153

154154
//! > expanded_code
155-
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 1, 0x30313233343536373839303132333435363738393031323334353637383930, 0x31323334, 4])
155+
core::panics::panic_with_byte_array(@"01234567890123456789012345678901234")
156156

157157
//! > diagnostics
158158

0 commit comments

Comments
 (0)