Skip to content

Commit ae98efd

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 b3f92bb commit ae98efd

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};
@@ -106,7 +107,7 @@ pub fn const_folding(
106107
},
107108
}
108109
let block = &mut lowered.blocks[BlockId(block_id)];
109-
let mut additional_consts = vec![];
110+
let mut additional_stmts = vec![];
110111
for stmt in block.statements.iter_mut() {
111112
ctx.maybe_replace_inputs(stmt.inputs_mut());
112113
match stmt {
@@ -141,9 +142,9 @@ pub fn const_folding(
141142
}
142143
Statement::Call(call_stmt) => {
143144
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)
145146
{
146-
*stmt = Statement::Const(updated_stmt);
147+
*stmt = updated_stmt;
147148
}
148149
}
149150
Statement::StructConstruct(StatementStructConstruct { inputs, output }) => {
@@ -214,7 +215,7 @@ pub fn const_folding(
214215
}
215216
}
216217
}
217-
block.statements.splice(0..0, additional_consts.into_iter().map(Statement::Const));
218+
block.statements.splice(0..0, additional_stmts);
218219

219220
match &mut block.end {
220221
FlatBlockEnd::Goto(_, remappings) => {
@@ -280,15 +281,15 @@ impl ConstFoldingContext<'_> {
280281
/// Handles a statement call.
281282
///
282283
/// 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
284285
/// 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
286287
/// is not enough.
287288
fn handle_statement_call(
288289
&mut self,
289290
stmt: &mut StatementCall,
290-
additional_consts: &mut Vec<StatementConst>,
291-
) -> Option<StatementConst> {
291+
additional_stmts: &mut Vec<Statement>,
292+
) -> Option<Statement> {
292293
let db = self.db;
293294
if stmt.function == self.panic_with_felt252 {
294295
let val = self.as_const(stmt.inputs[0].var_id)?;
@@ -297,6 +298,67 @@ impl ConstFoldingContext<'_> {
297298
.concretize(db, vec![GenericArgumentId::Constant(val.clone().intern(db))])
298299
.lowered(db);
299300
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+
}));
300362
}
301363
let (id, _generic_args) = stmt.function.get_extern(db)?;
302364
if id == self.felt_sub {
@@ -325,7 +387,7 @@ impl ConstFoldingContext<'_> {
325387
} else if self.div_rem_fns.contains(&id) {
326388
let lhs = self.as_int(stmt.inputs[0].var_id);
327389
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]));
329391
return Some(self.propagate_zero_and_get_statement(stmt.outputs[0]));
330392
}
331393
let rhs = self.as_int(stmt.inputs[1].var_id)?;
@@ -336,8 +398,9 @@ impl ConstFoldingContext<'_> {
336398
let r_output = stmt.outputs[1];
337399
let r_value = ConstValue::Int(r, self.variables[r_output].ty);
338400
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 }))
341404
} else if id == self.storage_base_address_from_felt252 {
342405
let input_var = stmt.inputs[0].var_id;
343406
if let Some(ConstValue::Int(val, ty)) = self.as_const(input_var) {
@@ -358,17 +421,20 @@ impl ConstFoldingContext<'_> {
358421
_ => None,
359422
};
360423
self.var_info.insert(stmt.outputs[0], VarInfo::Box(var_info.into()));
361-
Some(StatementConst {
424+
Some(Statement::Const(StatementConst {
362425
value: ConstValue::Boxed(const_value?.into()),
363426
output: stmt.outputs[0],
364-
})
427+
}))
365428
} else if id == self.unbox {
366429
if let VarInfo::Box(inner) = self.var_info.get(&stmt.inputs[0].var_id)? {
367430
let inner = inner.as_ref().clone();
368431
if let VarInfo::Const(inner) =
369432
self.var_info.entry(stmt.outputs[0]).insert_entry(inner).get()
370433
{
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+
}));
372438
}
373439
}
374440
None
@@ -377,7 +443,7 @@ impl ConstFoldingContext<'_> {
377443
let output = stmt.outputs[0];
378444
let value = ConstValue::Int(int_value.clone(), self.variables[output].ty);
379445
self.var_info.insert(output, VarInfo::Const(value.clone()));
380-
Some(StatementConst { value, output })
446+
Some(Statement::Const(StatementConst { value, output }))
381447
} else if id == self.array_new {
382448
self.var_info.insert(stmt.outputs[0], VarInfo::Array(vec![]));
383449
None
@@ -413,17 +479,17 @@ impl ConstFoldingContext<'_> {
413479
value: BigInt,
414480
output: VariableId,
415481
nz_ty: bool,
416-
) -> StatementConst {
482+
) -> Statement {
417483
let mut value = ConstValue::Int(value, self.variables[output].ty);
418484
if nz_ty {
419485
value = ConstValue::NonZero(Box::new(value));
420486
}
421487
self.var_info.insert(output, VarInfo::Const(value.clone()));
422-
StatementConst { value, output }
488+
Statement::Const(StatementConst { value, output })
423489
}
424490

425491
/// 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 {
427493
self.propagate_const_and_get_statement(BigInt::zero(), output, false)
428494
}
429495

@@ -603,11 +669,7 @@ impl ConstFoldingContext<'_> {
603669
let arm_idx = if value < &constrain_value { 0 } else { 1 };
604670
let output = info.arms[arm_idx].var_ids[0];
605671
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)],
611673
FlatBlockEnd::Goto(info.arms[arm_idx].block_id, Default::default()),
612674
))
613675
} else if id == self.array_get {
@@ -822,6 +884,8 @@ pub struct ConstFoldingLibfuncInfo {
822884
panic_with_felt252: FunctionId,
823885
/// The `core::panic_with_const_felt252` function.
824886
panic_with_const_felt252: FreeFunctionId,
887+
/// The `core::panics::panic_with_byte_array` function.
888+
panic_with_byte_array: FunctionId,
825889
/// Type ranges.
826890
type_value_ranges: OrderedHashMap<TypeId, TypeInfo>,
827891
/// The info used for semantic const calculation.
@@ -934,6 +998,10 @@ impl ConstFoldingLibfuncInfo {
934998
.generic_function_id("storage_base_address_const"),
935999
panic_with_felt252: core.function_id("panic_with_felt252", vec![]).lowered(db),
9361000
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),
9371005
type_value_ranges,
9381006
const_calculation_info: db.const_calc_info(),
9391007
}

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)